アロー関数式 は、その名のとおり矢印を使って記述し、function 式より短い構文で同様な内容を記述することができます。なおthisarguments, super, new.target を束縛しません。また、アロー関数式は、メソッドでない関数に最適で、コンストラクタとして使うことはできません。

構文

基本的な構文

(param1, param2, …, paramN) => { statements }
(param1, param2, …, paramN) => expression
         // 上記の式は、次の式と同等です: (param1, param2, …, paramN) => { 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

説明

hacks.mozilla.orgの "ES6 In Depth: Arrow functions" も参照してください。

2つの理由から、アロー関数が導入されました。1つ目の理由は関数を短く書きたいということで、2つ目の理由は this を束縛したくない、ということです。

関数の短縮形

var materials = [
  "Hydrogen",
  "Helium",
  "Lithium",
  "Beryl­lium"
];

materials.map(function(material) { 
  return material.length; 
}); // [8, 6, 7, 9]

materials.map((material) => {
  return material.length;
}); // [8, 6, 7, 9]

materials.map(({length}) => length); // [8, 6, 7, 9]

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 that = this;
  that.age = 0;

  setInterval(function growUp() {
    // このコールバックは、期待されるオブジェクトの値を
    // `that` 変数で参照する。
    that.age++;
  }, 1000);
}

あるいは、適切な this の値を対象の関数(上の例では growUp() 関数)に渡すように、束縛関数を作成することもできました。

アロー関数は this を束縛しないので、this は関数を囲っている外での this を意味します。そのため、setInterval に渡される関数の this の値は、外部関数の 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 は囲っているスコープでの同名変数への参照にすぎません。

var arguments = [1, 2, 3]; 
var arr = () => arguments[0]; 

arr(); // 1 

function foo(n) { 
  var f = () => arguments[0] + n; // foo は arguments を暗黙的に束縛している。 arguments[0] は n である。 
  return f(); 
}

foo(3); // 6 

多くの場合、残余引数arguments  オブジェクトの代わりに使えます。

function foo(n) { 
  var f = (...args) => args[0] + n; 
  return f(10); 
}

foo(1); // 11

メソッドとして使われるアロー関数

前に述べたように、アロー関数式は非メソッド型の関数に最もよく合っています。これをメソッドとして使った時のことを見てみましょう:

'use strict';

var obj = { 
  i: 10, 
  b: () => console.log(this.i, this), 
  c: function() { 
    console.log(this.i, this); 
  } 
};

obj.b(); // prints undefined, Window {...} (or the global object) 
obj.c(); // prints 10, Object {...} 

アロー関数は自身の this を持ちません。Object.defineProperty() を使う例は:

'use strict';
var obj = {
  a: 10
};

Object.defineProperty(obj, 'b', { 
  get: () => { 
    console.log(this.a, typeof this.a, this); // undefined 'undefined' Window {...} (or the global object) 
    return this.a + 10; // represents global object 'Window', therefore 'this.a' returns 'undefined' 
  } 
});

new 演算子の使用

アロー関数はコンストラクタとして使用できず、 new と共に使うとエラーになります。

var Foo = () => {};
var foo = new Foo(); // TypeError: Foo is not a constructor

prototype プロパティの使用

アロー関数には prototype プロパティはありません。

var Foo = () => {};
console.log(Foo.prototype); // undefined

yield キーワードの使用

yield キーワードはアロー関数の本体で使用されないでしょう (内部で入れ子になった関数が許可されている場合を除く)。結果として、アロー関数はジェネレータとして使用できません。

関数の Body 部分

アロー関数は、"簡潔文体 (concise body)" か、もしくはより一般的な "ブロック文体 (block body)" のどちらかを使用することができます。

簡潔文体 (concise body) においては、単一の式だけが記述できるので、その式が明示的に return される値となります。しかし、ブロック文体においては、自動的に return はされないので、明示的に return 文を使用する必要があります。

var func = x => x * x;                  // 簡潔構文の場合、明示せずとも"return" されます
var func = (x, y) => { return x + y; }; // ブロック文体では、明示的に "return" を宣言する必要があります

オブジェクトリテラルを返す

短縮構文 params => {object:literal} を使ってオブジェクトリテラルを返そうとしても、期待通りに動作しないことに注意しましょう。

var func = () => {  foo: 1  };
// 呼び出した func() は undefined を返す!

var func = () => {  foo: function() {}  };
// SyntaxError: function 文には名前が必要

これは、括弧 ({}) 内のコードが文の列として構文解析されてしまっているからです(つまり、foo はオブジェクトリテラル内のキーでなく、ラベルとして扱われています)。

オブジェクトリテラルは括弧で囲むのを忘れないでください。

var func = () => ({ foo: 1 });

改行

アロー関数には括弧とアロー(矢印)の間に改行を入れられません。

var func = ()
           => 1; 
// SyntaxError: expected expression, got '=>'

解析の順序

アロー関数内のアロー(矢印)はオペレーターではないですが、アロー関数は通常の関数と異なり、オペレーターを引き継いだ特別な解析ルールを持ちます。

let callback;

callback = callback || function() {}; // ok

callback = callback || () => {};      
// SyntaxError: invalid arrow-function arguments

callback = callback || (() => {});    // ok

さらなる例

// 空のアロー関数は undefined を返します
let empty = () => {};

(() => "foobar")()
// "foobar" を返します
// (this is an Immediately Invoked Function Expression 
// see 'IIFE' in glossary)

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 => {
   // ...
});

// 見た目に解析が簡単な引数なしのアロー関数
setTimeout( () => {
  console.log('I happen sooner');
  setTimeout( () => {
    // deeper code
    console.log('I happen later');
  }, 1);
}, 1);

仕様

仕様書 状態 コメント
ECMAScript 2015 (6th Edition, ECMA-262)
Arrow Function Definitions の定義
標準 初期定義
ECMAScript Latest Draft (ECMA-262)
Arrow Function Definitions の定義
ドラフト  

ブラウザの実装状況

Update compatibility data on GitHub
デスクトップモバイルサーバー
ChromeEdgeFirefoxInternet ExplorerOperaSafariAndroid webviewAndroid 版 ChromeEdge MobileAndroid 版 FirefoxAndroid 版 OperaiOS 版 SafariSamsung InternetNode.js
基本対応Chrome 完全対応 45Edge 完全対応 ありFirefox 完全対応 22
補足
完全対応 22
補足
補足 The initial implementation of arrow functions in Firefox made them automatically strict. This has been changed as of Firefox 24. The use of 'use strict'; is now required.
補足 Prior to Firefox 39, a line terminator (\n) was incorrectly allowed after arrow function arguments. This has been fixed to conform to the ES2015 specification and code like () \n => {} will now throw a SyntaxError in this and later versions.
IE 未対応 なしOpera 完全対応 32Safari 完全対応 10WebView Android 完全対応 45Chrome Android 完全対応 45Edge Mobile 完全対応 ありFirefox Android 完全対応 22
補足
完全対応 22
補足
補足 The initial implementation of arrow functions in Firefox made them automatically strict. This has been changed as of Firefox 24. The use of 'use strict'; is now required.
補足 Prior to Firefox 39, a line terminator (\n) was incorrectly allowed after arrow function arguments. This has been fixed to conform to the ES2015 specification and code like () \n => {} will now throw a SyntaxError in this and later versions.
Opera Android 完全対応 32Safari iOS 完全対応 10Samsung Internet Android 完全対応 5.0nodejs 完全対応 あり
Trailing comma in parametersChrome 完全対応 58Edge ? Firefox 完全対応 52IE 未対応 なしOpera 完全対応 45Safari ? WebView Android 完全対応 58Chrome Android 完全対応 58Edge Mobile ? Firefox Android 完全対応 52Opera Android 完全対応 45Safari iOS ? Samsung Internet Android 完全対応 7.0nodejs 完全対応 あり

凡例

完全対応  
完全対応
未対応  
未対応
実装状況不明  
実装状況不明
実装ノートを参照してください。
実装ノートを参照してください。

関連項目

ドキュメントのタグと貢献者

最終更新者: shootaroo,