JavaScriptのアロー関数:Arrow function expressions
ES6(ES2015)で導入されたJavaScriptのアロー関数(Arrow function expressions)とは何か、アロー関数の使い方、通常の関数との違い、そしてアロー関数を使用する理由について解説します。
JavaScriptのアロー関数導入の背景
「アロー関数(Arrow function)」という用語は、「アロー関数式(Arrow function expressions)」とも呼ばれます。どちらも公式に使用されている用語ですが、本記事では「アロー関数」として統一して説明します。
JavaScriptのアロー関数は、ECMAScript 6(ES6)で導入されました。ES6は2015年に発行されたECMAScript標準の第6版であり、多くの機能追加や改善点が含まれています。
アロー関数は、JavaScriptで従来使われていた関数宣言や関数式よりも簡潔で使いやすくするために考案されました。C++、Python、Javaなどの様々な言語で使われているラムダ関数(lambda function)のアイデアをJavaScriptの文法で表現したものです。このようにアロー関数を導入することで、関数型プログラミングのスタイルがより強化され、コードをより簡潔かつ可読性高く記述できるようになりました。
しかし、アロー関数にはいくつかの制限があり、すべての状況で使用できるわけではありません。(以下の内容はMDN:アロー関数式からの抜粋です。)
アロー関数の制限点
this
,arguments
,super
に対する独自のバインディングがなく、メソッドとして使用してはいけません。new.target
キーワードはありません。- 一般的にスコープを指定する際に使われる
call()
、apply()
、bind()
メソッドは利用できません。 - コンストラクタ関数として使用できません。
yield
はアロー関数の内部で使用できません。
これらの制限点はデメリットと見なされることもありますが、一方でアロー関数を使う利点とも考えられます。
アロー関数の使い方
avaScriptにおけるアロー関数の定義方法や、どのような構文・書式で記述するかを説明します。
アロー関数の定義
JavaScriptにおけるアロー関数は、関数を変数に代入して使用する関数式の一種です。関数宣言では定義できません。
function add(a, b) {
return a + b;
};
add(1, 2); // 3
const add = function(a, b) {
return a + b;
};
add(1, 2); // 3
const add = (a, b) => {
return a + b;
};
add(1, 2); // 3
アロー関数は、function
キーワードの代わりに=>
記号(アロー)を使って関数を定義し、従来の関数よりも簡単で簡潔に記述できます。
アロー関数特有の構文
通常の関数と比較すると、アロー関数は特有の構文を持っています。
- 引数が1つの場合、丸括弧()を省略できます。
- 関数の内部が単一の式(single expression)の場合、
return
キーワードを省略できます。return
キーワードを省略する場合は、波括弧{}も必ず省略しなければなりません。 - 重複した引数名を宣言することはできません。
引数が1つの場合、丸括弧()を省略できます。
// 引数が1つだけの場合、丸括弧()は省略可能です。
const func = param => {...} // 丸括弧を省略した書き方
// 上記の表現は次のように解釈されます。
const func = (param) => {...} // 丸括弧を省略していない書き方
注意してください!引数がない場合は、丸括弧()を省略できません。
関数の内部が単一の式(single expression)の場合、return
キーワードを省略できます。
onst add = (a, b) => a + b; // returnキーワードを省略する場合、波括弧{}も必ず省略しなければなりません。
// 上記の表現は次のように解釈されます。
const add = (a, b) => { return a + b; };
注意してください!関数の内部が単一の式(single expression)でない場合、return
キーワードを省略できません。
const add = (a, b) => {
const sum = a + b;
console.log("Sum:", sum);
// returnキーワードは省略できません。
return sum;
};
const result = add(3, 5);
console.log("Result:", result); // 結果: Sum: 8, Result: 8
重複した引数名を宣言することはできません。
// 誤った使用例:重複した引数名
const multiply = (x, y, x) => {
return x * y;
};
通常の関数でstrict mode
を適用していない場合、重複した引数名を使用してもJavaScriptエンジンはエラーを発生させません。しかし、アロー関数では常に重複した引数名を宣言することはできません。
アロー関数と通常の関数の違い
先に説明した文法的な違い以外に、アロー関数と通常の関数の違いについて説明します。
ここでは特に重要な(必ず知っておくべき)いくつかのポイントに絞って解説します。
通常の関数との違い
- アロー関数はインスタンスを生成できません。つまり、コンストラクタ関数として使用できません。
- アロー関数は独自の
this
を持ちません。 - アロー関数は
arguments
オブジェクトを持ちません。
アロー関数はインスタンスを生成できません。
const Person = (name) => {
this.name = name;
};
const john = new Person("John"); // エラー発生:Person is not a constructor
アロー関数は通常の関数とは異なり、インスタンスを生成できません。non-constructorであるためです。そのため、prototype
プロパティを持たず、プロトタイプも生成しません。
const Person = (name) => {
this.name = name;
};
console.log(Person.hasOwnProperty("prototype")); // false
アロー関数は独自のthis
を持ちません。
<!DOCTYPE html>
<html>
<head>
<title>Event Listener Example</title>
</head>
<body>
<button id="myButton">Click Me</button>
<script src="event.js"></script>
</body>
</html>
const myButton = document.getElementById('myButton');
// 通常の関数を使ったイベントハンドラ
myButton.addEventListener("click", function() {
console.log("通常関数でクリックされました。this: " + this.textContent);
});
// アロー関数を使ったイベントハンドラ
myButton.addEventListener("click", () => {
console.log("アロー関数でクリックされました。thisのテキスト: " + this.textContent);
});
addEventListener
を使用してイベントを処理する際、コールバック関数内のthis
はそのイベントが発生したDOM要素を指します。通常の関数とアロー関数を使ってイベントハンドラを定義すると、this
が指す対象が異なります。
上記の例では、myButton
要素に2つのイベントハンドラを追加しています。最初のハンドラは通常の関数を使って定義し、2番目のハンドラはアロー関数を使って定義しています。
ボタンをクリックすると、2つのハンドラが両方とも実行されます。最初のハンドラのthis
はmyButton
要素を指し、this.textContent
はボタンのテキスト「Click Me」を出力します。
しかし、2番目のイベントハンドラはアロー関数を使用しており、ボタンをクリックすると「Clicked using arrow function. This text: undefined」と出力されます。これはアロー関数のthis
がグローバルコンテキストを指しているためです。したがって、イベントハンドラ内でthis
を使う必要がある場合は、通常の関数を使用するべきです。
したがって、イベントハンドラ内でthis
が必要な場合は通常の関数を使うのが適切であり、アロー関数を使う場合は注意が必要です。アロー関数は主にthis
を使用しない場合や、外部スコープのthis
をそのまま利用するときに便利です。
アロー関数はarguments
オブジェクトを持ちません。
function sumWithArguments() {
let sum = 0;
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
return sum;
}
const sumWithArrow = () => {
let sum = 0;
for (let i = 0; i < arguments.length; i++) {
sum += arguments[i]; // ここで arguments を使うとエラーになります。
}
return sum;
}
console.log(sumWithArguments(1, 2, 3, 4, 5)); // 出力: 15
console.log(sumWithArrow(1, 2, 3, 4, 5)); // エラー発生: arguments is not defined
arguments
オブジェクトは関数内で引数にアクセスするために使われますが、通常の関数ではこのオブジェクトを使用できますが、アロー関数では使用できません。
sumWithArguments
関数は通常の関数として宣言されており、arguments
オブジェクトを使って引数の合計を計算します。しかし、sumWithArrow
関数はアロー関数として宣言されているため、arguments
を使おうとするとエラーが発生します。これはアロー関数が独自のarguments
オブジェクトを持っていないためです。したがって、引数にアクセスする必要がある場合は、アロー関数よりも通常の関数を使うことが望ましいです。
アロー関数を使う理由
既存の関数と比較すると、アロー関数は短い構文で関数をより簡潔に表現できます。
多くの開発者は、短くてわかりやすいコードを好みます。
次に、メソッド内でアロー関数を使用すると、アロー関数は独自の this
を持たず、外側のスコープから this
を継承するため、this
に関する問題を回避しつつ、より簡潔にコードを書くことができます。以下の例を通して説明いたします。
const myObj = {
name: "山田太郎",
func: function() {
console.log(this.name); // 出力: "山田太郎"
/* 通常の関数を使用 */
setTimeout(function() {
console.log(this); // 出力: window オブジェクト(ブラウザ環境の場合)
console.log(this.name); // エラーまたは undefined(出力されない)
}, 1000);
/* 通常の関数を使用 */
setTimeout(function() {
console.log(this); // 出力: myObj オブジェクト
console.log(this.name); // 出力: "山田太郎"
}.bind(this), 1000); // this を明示的に myObj にバインドする必要がある
},
arrow_func: function() {
console.log(this.name); // 出力: "山田太郎"
/* アロー関数を使用 */
setTimeout(() => {
console.log(this); // 出力: myObj オブジェクト
console.log(this.name); // 出力: "山田太郎"
}, 1000);
}
};
myObj.func();
myObj.arrow_func();
上記のコード例を見ると、アロー関数を使用することで、メソッド内部での this
を明示的にバインドする必要がなくなり、より簡潔かつ便利にコードを記述できることがわかります。この例は、アロー関数が通常の関数と比較して this
に関する問題を解決するのに有効であることを示しています。
ただし、this
の扱いについては、状況によっては通常の関数の方が便利な場合もあります。そのため、開発者は状況に応じて通常の関数を使うか、アロー関数を使うかを選択する必要があります。すべてのコードに言えることですが、一概にどちらが常に優れているとは限りません。
仕様書
仕様書 | |
---|---|
アロー関数の定義 |
ECMAScript Language Specification #sec-arrow-function-definitions |
ブラウザ互換性
構文 |
デスクトップ Chrome
|
デスクトップデスクトップ Edge
|
デスクトップ Firefox
|
Safari
|
---|---|---|---|---|
アロー関数
|
45 | 12 | 22 | 10 |