MDN wants to talk to developers like you: https://qsurvey.mozilla.com/s3/8d22564490d8

箭頭函數 (Arrow Function)

This is a new technology, part of the ECMAScript 2015 (ES6) standard.
This technology's specification has been finalized, but check the compatibility table for usage and implementation status in various browsers.

箭頭函數表示式 (Arrow function expression,也是所謂的 fat arrow function) 比起一般的函數表示式擁有更短的語法以及詞彙上綁定 this 變數,所有的箭頭函數都是無名函數 (anonymous function).

基本語法

(param1param2, …, paramN) => { statements } 
(param1param2, …, paramN) => expression
     // 等於 :  => { return expression; } 

// 只有一個參數時,括號才能不加:
(singleParam) => { statements }
singleParam => { statements }

//若無參數,就一定要加括號:
() => { statements }

進階語法

// 用大括號將內容括起來,返回一個物件實字表示法:
params => ({foo: bar}) 

// Rest parameters and default parameters are supported  
(param1param2...rest) => { statements } 
(param1 = defaultValue1param2, …, paramN = defaultValueN) => { 
statements } 

// Destructuring within the parameter list is also supported 
var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c; f(); // 6

詳細語法範例請參照這裡

param
參數名稱。多個參數以()包住,如不需要參數則以 () 表示, 如只有一個參數可以省略括弧 (如 foo => 1)。
statements or expression
當有多個陳述 (statement) 需用 { } 框住,當只有一個陳述則不需;其中表示式 (Expression) 最後也會是箭頭函數的返回值。

說明

也可參閱  "ES6 In Depth: Arrow functions" on hacks.mozilla.org.

箭頭函數有兩個重要的特性:更短的函數寫法this 變數綁定。

更短的函數寫法

比較一般寫法和箭頭函數寫法;In some functional patterns, shorter functions are welcome. Compare:

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

var materialsLength1 = material.map(function(material) { 
  return material.length;
});

var materialsLength2 = material.map((material) => {
  return material.length;
});

var materialsLength3 = material.map(material => material.length);

this 變數綁定

在過去,函數的 this 變數在不同狀況下一直指向不同值  (例如當建構子呼叫時指向的是新建構的物件、undefined 在 strict 模式、當以物件方法呼叫時指向呼叫物件),這樣的特性對物件導向程式設計來說其實相當麻煩。

function Person() {
  // 這個 Person() 建構式定義 `this` 為它自己
  this.age = 0;

  setInterval(function growUp() {
    // 在 nonstrict 模式, growUp() 函式定義了 `this` 為
    // global object, 而不是 Person() 建構式所定義的 `this`
    this.age++;
  }, 1000);
}

var p = new Person();

為了解決這個問題,常見的方法是利用 closure 將 this 變數存入另一個變數之中:

function Person() {
  var self = this; // 有些人喜歡 `that` 而不是 `self`. 
                   // 選好一種取法後始終如一
  self.age = 0;

  setInterval(function growUp() {
    // 這個 callback 參考 `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; // 或是 global 物件

但其於 strict 模式作用仍存在。

由 call 與 apply 函數呼叫

於 this 變數已被綁定,所以透過 callapply 呼叫箭頭函數只能傳入參數,但無法改變 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));         // This would log to 2
console.log(adder.addThruCall(1)); // This would log to 2 still

不綁定任何參數

箭頭函數並不綁定 arguments object。所以在這個範例,arguments 只是參考到 enclosing scope 相同的變數。

var arguments = 42;
var arr = () => arguments;

arr(); // 42

function foo() {
  var f = (i) => arguments[0] + i; // foo 的隱含 arguments 綁定
  return f(2);
}

foo(1); // 3

大多時候,使用 rest parameters 是個比較好的、取代 arguments object 的方式。

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

foo(1); // 2

將箭頭函數撰寫為方法

As stated previously, arrow function expressions are best suited for non-method functions. Let's see what happens when we try to use them as methods:

'use strict';
var obj = {
  i: 10,
  b: () => console.log(this.i, this),
  c: function() {
    console.log(this.i, this);
  }
}
obj.b(); // prints undefined, Object {...}
obj.c(); // prints 10, Object {...}

Arrow functions do not define ("bind") their own this. Another example involving Object.defineProperty():

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

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

Use of the new operator

Arrow functions cannot be used as constructors and will throw an error when used with new.

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

Use of prototype property

Arrow functions do not have a prototype property.

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

Use of the yield keyword

The yield keyword may not be used in an arrow function's body (except when permitted within functions further nested within it). As a consequence, arrow functions cannot be used as generators.

Function body

Arrow functions can have either a "concise body" or the usual "block body".

In a concise body, only an expression is needed, and an implicit return is attached. In a block body, you must use an explicit return statement.

var func = x => x * x;                  // concise syntax, implied "return"
var func = (x, y) => { return x + y; }; // with block body, explicit "return" needed

Returning object literals

Keep in mind that returning object literals using the concise syntax params => {object:literal} will not work as expected.

var func = () => { foo: 1 };               // Calling func() returns undefined!
var func = () => { foo: function() {} };   // SyntaxError: function statement requires a name

This is because the code inside braces ({}) is parsed as a sequence of statements (i.e. foo is treated like a label, not a key in an object literal).

Remember to wrap the object literal in parentheses.

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

Line breaks

An arrow function cannot contain a line break between its parameters and its arrow.

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

Parsing order

Although the arrow in an arrow function is not an operator, arrow functions have special parsing rules that interact differently with operator precedence compared to regular functions.

let callback;

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

 

更多範例

// An empty arrow function returns undefined
let empty = () => {};

(() => "foobar")() // returns "foobar" 

var simple = a => a > 15 ? 15 : a; 
simple(16); // 15
simple(10); // 10

let max = (a, b) => a > b ? a : b;

// Easy array filtering, mapping, ...

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]

規範標準

Specification Status Comment
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Arrow Function Definitions' in that specification.
Standard Initial definition.

瀏覽器相容性

Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support No support 22.0 (22.0) No support No support No support
Feature Android Chrome for Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support No support No support 22.0 (22.0) No support No support No support

Firefox 特定註記

  • 在 Firefox 24 前,strict mode 會隨著箭頭函數定義而生效,但之後已取消,明白宣告 strict mode 是需要的。
  • 箭頭函數和 Firefox3 加入、非標準的 Expression Closures (詳細資訊: Javascript 1.8) 有所不同,針對 Expression Closures 並無綁定 this 變數。
  • 在 Firefox 39 前, 單行終結符號 (\n) 錯誤地必允許在箭頭函數,現在這項錯誤已經修正以符合 ES6 標準,類似程式碼如 () \n => {} 將導致 SyntaxError 錯誤。

文件標籤與貢獻者

 此頁面的貢獻者: tonykuo, yungtah, Snailpool, wkliang, linjimmy168, foxbrush
 最近更新: tonykuo,