2017年1月25日 星期三

(js)箭頭函數

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

基本語法

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

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

//若無參數,就一定要加括號:
() => { statements }
詳細語法範例請參照這裡
param
參數名稱。多個參數以()包住,如不需要參數則以 () 表示, 如只有一個參數可以省略括弧 (如 foo => 1)。
statements or expression
當有多個陳述 (statement) 需用 { } 框住,當只有一個陳述則不需;其中表示式 (Expression) 最後也會是箭頭函數的返回值。

說明

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

更短的函數寫法

比較一般寫法和箭頭函數寫法;In some functional patterns, shorter functions are welcome. Compare:
var a = [
  "Hydrogen",
  "Helium",
  "Lithium",
  "Beryl­lium"
];

var a2 = a.map(function(s){ return s.length });

var a3 = a.map( s => s.length );

this 變數綁定

在過去,函數的 this 變數在不同狀況下一直指向不同值  (例如當建構子呼叫時指向的是新建構的物件、undefined 在 strict 模式、當以物件方法呼叫時只向呼叫物件),這樣的特性對物件導向程式設計來說其實相當麻煩。
function Person() {
  // The Person() constructor defines `this` as itself.
  this.age = 0;

  setInterval(function growUp() {
    // In nonstrict mode, the growUp() function defines `this` 
    // as the global object, which is different from the `this`
    // defined by the Person() constructor.
    this.age++;
  }, 1000);
}

var p = new Person();
為了解決這個問題,常見的方法是利用 closure 將 this 變數存入另一個變數之中:
function Person() {
  var self = this; // Some choose `that` instead of `self`. 
                   // Choose one and be consistent.
  self.age = 0;

  setInterval(function growUp() {
    // The callback refers to the `self` variable of which
    // the value is the expected object.
    self.age++;
  }, 1000);
}
或者是,透過綁定函數的作法來綁定 this 變數到 growUp 函數。
不過現在箭頭函數會自動將 this 變數綁定到其定義時所在的物件,如下所示:
function Person(){
  this.age = 0;

  setInterval(() => {
    this.age++; // |this| properly refers to the person object
  }, 1000);
}

var p = new Person();

和 Strict 模式

由於 this 變數具有詞彙上綁定義意,所以 strict 模式的宣告對 this 的作用將被忽略。
var f = () => {'use strict'; return this};
f() === window; // or the global object
但其於 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));         // This would log to 2
console.log(adder.addThruCall(1)); // This would log to 2 still

Examples

// 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]

規範標準

SpecificationStatusComment
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Arrow Function Definitions' in that specification.
StandardInitial definition.

瀏覽器相容性

FeatureChromeFirefox (Gecko)Internet ExplorerOperaSafari
Basic supportNo support22.0 (22.0)No supportNo supportNo support

Firefox 特定註記

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

文件標籤與貢獻者

 此頁面的貢獻者: linjimmy168foxbrush