アロー関数式 は、function 式 と比べてより短い構文を持ち、this の値を語彙的に束縛します (ただし、自身の this や arguments, super, new.target は束縛しません)。アロー関数は、常に 匿名関数 です。
構文
基本構文
(param1, param2, …, paramN) => { statements } (param1, param2, …, paramN) => expression // これと等価: => { return expression; } // 引数を 1 個しか取らない場合、丸括弧 () は任意です: (singleParam) => { statements } singleParam => { statements } // 引数を取らない場合、丸括弧が必要です: () => { statements }
高等構文
// object リテラル式を返す場合は、本体を丸括弧 () で囲みます: params => ({foo: bar}) // 残りの引数 と デフォルト引数 がサポートされます (param1, param2, ...rest) => { statements } (param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements } // 引数リスト内の 分割代入 もサポートされます var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c; f(); // 6
詳しい構文の例は、ES Wiki の harmony:arrow_function_syntax を参照してください。
説明
hacks.mozilla.org サイトの "ES6 In Depth: Arrow functions" も参照してください。
アロー関数の導入には 2 つの因子が作用します。短い関数と語彙的な this
です。
短い関数
いくつかの関数パターンでは、短い関数が望まれます。次のコードを比べてください。
var a = [ "Hydrogen", "Helium", "Lithium", "Beryllium" ]; var a2 = a.map(function(s){ return s.length }); var a3 = a.map( s => s.length );
語彙的な this
アロー関数が登場する前まで、それぞれの新しい関数は自身の this の値を定義していました。(コンストラクタでは新しいオブジェクト、strict モード の関数呼び出しでは undefined、関数が "オブジェクトのメソッド" として呼び出された場合はコンテキストのオブジェクト、他)。これは、オブジェクト指向プログラミングをする上で煩わしいものであることが判明しました。
function Person() { // Person() のコンストラクタは、自身のインスタンスを `this` として定義します。 this.age = 0; setInterval(function growUp() { // 非 strict モードでは、growUp() 関数は `this` をグローバルオブジェクトとして定義します。 // これは、 Person() コンストラクタで定義された `this` とは異なります。 this.age++; }, 1000); } var p = new Person();
ECMAScript 3/5 において、この問題は this
の値をスコープ内の変数に割り当てることにより修正されました。
function Person() { var self = this; // `self` の代わりに `that` を選ぶこともあります。 // どちらかに統一するようにしましょう。 self.age = 0; setInterval(function growUp() { // このコールバックは、期待されるオブジェクトの値を // `self` 変数で参照します。 self.age++; }, 1000); }
また、束縛された関数 が生成されるため、しかるべき this
の値が growUp()
関数に渡されます。
アロー関数がスコープ内の this
の値を捕捉するため、以下のコードは期待通りに動きます。
function Person(){ this.age = 0; setInterval(() => { this.age++; // |this| は person オブジェクトを適切に参照します。 }, 1000); } var p = new Person();
strict モードの関連事項
語彙的な this
が与えられた場合、strict モード の規則は this
を単に無視されたものとみなします。
var f = () => {'use strict'; return this}; f() === window; // またはグローバルオブジェクト
他の strict モードの規則は通常通り適用されます。
call や apply からの呼び出し
this
はすでに語彙的に束縛されているため、call()
や apply()
メソッドを介してアロー関数が呼ばれた場合、引数で渡されるだけなので this
は影響を受けません:
var adder = { base : 1, add : function(a) { var f = v => v + this.base; return f(a); }, addThruCall: function(a) { var f = v => v + this.base; var b = { base : 2 }; return f.call(b, a); } }; console.log(adder.add(1)); // これは 2 を出力します console.log(adder.addThruCall(1)); // これも 2 を出力します
語彙的な arguments
アロー関数は、arguments
オブジェクト をコードに露出しません: arguments.length
, arguments[0]
, arguments[1]
および他のオブジェクトは、アロー関数の呼び出し時に提供された arguments を参照しません。代わりに、arguments
は閉じたスコープ内の名前への単なる参照になります。
var arguments = 42; var arr = () => arguments; arr(); // 42 function foo() { var f = (i) => arguments[0]+i; // foo は arguments バインドを省略します return f(2); } foo(1); // 3
アロー関数は自身の arguments
オブジェクトを持ちませんが、多くの場合、残りの引数 が良い代替になります:
function foo() { var f = (...args) => args[0]; return f(2); } foo(1); // 2
yield
キーワードの使用
yield
キーワードはアロー関数の本体で使用されないでしょう (内部で入れ子になった関数が許可されている場合を除く)。結果として、アロー関数はジェネレータとして使用できません。
関数本体
アロー関数は、"簡潔文体 (concise body)" または通常の "ブロック文体 (block body)" のどちらかを持ちます。
ブロック文体は、自動的に値を返しません。明示的に return
文を使用する必要があります:
var func = x => x * x; // 簡潔構文、"return" を暗に含みます var func = (x, y) => { return x + y; }; // ブロック文体では明示的な "return" が必要です
object リテラルを返す
object リテラルを返す時に簡潔な構文 params => {object:literal}
を使うと、期待通りに動作しないことに留意してください:
var func = () => { foo: 1 }; // 呼び出した func() は undefined を返します! var func = () => { foo: function() {} }; // 構文エラー: function 文は名前が必要です
これは、括弧 ({}) 内部のコードは、object ではなく、文として順に解析されることが理由です。(つまり、foo
は、object リテラル内のキーではなく、ラベルのように扱われます。)
object リテラルを括弧で囲むことを覚えてください:
var func = () => ({ foo: 1 });
例
// 空のアロー関数は undefined を返します let empty = () => {}; (() => "foobar")() // "foobar" を返します var simple = a => a > 15 ? 15 : a; simple(16); // 15 simple(10); // 10 let max = (a, b) => a > b ? a : b; // 簡単な配列のフィルタリング、マッピング等 var arr = [5, 6, 13, 0, 1, 18, 23]; var sum = arr.reduce((a, b) => a + b); // 66 var even = arr.filter(v => v % 2 == 0); // [6, 0, 18] var double = arr.map(v => v * 2); // [10, 12, 26, 0, 2, 36, 46] // さらに簡潔な promise チェーン promise.then(a => { // ... }).then(b => { // ... });
仕様
仕様書 | 状態 | コメント |
---|---|---|
ECMAScript 2015 (6th Edition, ECMA-262) Arrow Function Definitions の定義 |
標準 | Initial definition. |
ECMAScript 2017 Draft (ECMA-262) Arrow Function Definitions の定義 |
ドラフト |
ブラウザの実装状況
機能 | Chrome | Firefox (Gecko) | Edge | IE | Opera | Safari |
---|---|---|---|---|---|---|
基本サポート | 45.0 | 22.0 (22.0) | (有) |
未サポート |
32 | 未サポート |
機能 | Android | Android Webview | Firefox Mobile (Gecko) | IE Mobile | Opera Mobile | Safari Mobile | Chrome for Android |
---|---|---|---|---|---|---|---|
基本サポート | 未サポート | 45.0 | 22.0 (22.0) | 未サポート | 未サポート | 未サポート | 45.0 |
Firefox の特記事項
- Firefox におけるアロー関数の初期実装は、関数を自動的に strict にしました。これは Firefox 24 で変更され、
"use strict";
の使用が必須になりました。 - アロー関数は、Firefox 3 で追加された非標準の 式クロージャ (詳細: JavaScript 1.8) と意味的に異なり、式クロージャ では
this
を語彙的に束縛しません。 - Firefox 39 より前は、行端記号 (
\n
) がアロー関数の引数の後で誤って許可されていました。これは、バージョン 39 以降で ES6 仕様に準拠するように修正され、() \n => {}
のようなコードがSyntaxError
を投げるようになりました。
関連項目
- hacks.mozilla.org サイトの "ES6 In Depth: Arrow functions"