es6之箭頭函數

箭頭函數

es6的箭頭函數,顧名思義箭頭函數是使用一個箭頭( => )來定義的函數,這很容易理解可是它有不少行爲與傳統的js函數不一樣:node

  • 沒有 this 、 super 、 arguments 。
  • 不能被使用 new 調用: 箭頭函數沒有 [[Construct]] 方法,所以不能被用爲構造函數,使用 new 調用箭頭函數會拋出錯誤。
  • 沒有原型: 既然不能對箭頭函數使用 new ,那麼它也不須要原型,也就是沒有prototype 屬性。
  • 不能更改 this : this 的值在函數內部不能被修改,在函數的整個生命週期內其值會保持不變。
  • 沒有 arguments 對象: 既然箭頭函數沒有 arguments 綁定,你必須依賴於具名參數或剩餘參數來訪問函數的參數
  • 不容許重複的具名參數: 箭頭函數不容許擁有重複的具名參數,不管是否在嚴格模式下;而相對來講,傳統函數只有在嚴格模式下才禁止這種重複

箭頭函數的語法

var reflect = value => value;
// 有效等價於:
var reflect = function(value) {
return value;
};

函數須要傳入多個參數:es6

var sum = (num1, num2) => num1 + num2;
// 有效等價於:
var sum = function(num1, num2) {
return num1 + num2;
};

若是函數沒有任何參數,那麼在聲明時就必須使用一對空括號,就像這樣:瀏覽器

var getName = () => "Nicholas";
// 有效等價於:
var getName = function() {
return "Nicholas";
};

你基本能夠將花括號內部的代碼當作傳統函數那樣對待,除了 arguments 對象不可用以外。
若你想建立一個空函數,就必須使用空的花括號,就像這樣:閉包

var doNothing = () => {};
// 有效等價於:
var doNothing = function() {};

花括號被用於表示函數的主體,它在你至今看到的例子中都工做正常。但若箭頭函數想要從
函數體內向外返回一個對象字面量,就必須將該字面量包裹在圓括號內,例如:app

var getTempItem = id => ({ id: id, name: "Temp" });
// 有效等價於:
var getTempItem = function(id) {
return {
id: id,
name: "Temp"
};
};

沒有this綁定

JS 最多見的錯誤領域之一就是在函數內的 this 綁定。因爲一個函數內部的 this 值能夠
被改變,這取決於調用該函數時的上下文,所以徹底可能錯誤地影響了一個對象,儘管你本
意是要修改另外一個對象。
箭頭函數沒有 this 綁定,意味着箭頭函數內部的 this 值只能經過查找做用域鏈來肯定。
若是箭頭函數被包含在一個非箭頭函數內,那麼 this 值就會與該函數的相等;不然,
this 值就會是全局對象(在瀏覽器中是 window ,在 nodejs 中是 global )。函數

沒有arguments綁定

儘管箭頭函數沒有本身的 arguments 對象,但仍然能訪問包含它的函數的 arguments 對
象。不管此後箭頭函數在何處執行,該對象都是可用的。例如:優化

function createArrowFunctionReturningFirstArg() {
return () => arguments[0];
}
var arrowFunction = createArrowFunctionReturningFirstArg(5);
console.log(arrowFunction()); // 5

也像對其餘函數那樣,你仍然能夠對箭頭函數使用 call() 、 apply() 與 bind() 方法,雖

然函數的 this 綁定並不會受影響。這裏有幾個例子:this

var sum = (num1, num2) => num1 + num2;
console.log(sum.call(null, 1, 2)); // 3
console.log(sum.apply(null, [1, 2])); // 3
var boundSum = sum.bind(null, 1, 2);
console.log(boundSum()); // 3

尾調用優化

在 ES6 中對函數最有趣的改動或許就是一項引擎優化,它改變了尾部調用的系統。尾調用(
tail call )指的是調用函數的語句是另外一個函數的最後語句,就像這樣:prototype

function doSomething() {
return doSomethingElse(); // 尾調用
}

在 ES5 引擎中實現的尾調用,其處理就像其餘函數調用同樣:一個新的棧幀( stack frame
)被建立並推到調用棧之上,用於表示該次函數調用。這意味着以前每一個棧幀都被保留在內
存中,當調用棧太大時會出問題。code

那何時不會被優化呢/

  • 一個小改動——不返回結果(缺乏return),就會產生一個沒法被優化的函數:
"use strict";
function doSomething() {
// 未被優化:缺乏 return
doSomethingElse();
}
  • 若是你的函數在尾調用返回結果以後進行了額外操做,那麼該函數也沒法被優化:
"use strict";
function doSomething() {
// 未被優化:在返回以後還要執行加法
return 1 + doSomethingElse();
}
  • 關閉優化的另外一個常見方式,是將函數調用的結果儲存在一個變量上,以後才返回告終果,就像這樣:
"use strict";
function doSomething() {
// 未被優化:調用並不在尾部
var result = doSomethingElse();
return result;
}

本例之因此不能被優化,是由於 doSomethingElse() 的值並無當即被返回。

  • 使用閉包或許就是須要避免的最困難狀況,由於閉包可以訪問上層做用域的變量,會致使尾調用優化被關閉。例如:
"use strict";
function doSomething() {
var num = 1,
func = () => num;
// 未被優化:此函數是閉包
return func();
}

"use strict";
function doSomething() {
var num = 1,
func = () => num;
// 未被優化:此函數是閉包
return func();
}

此例中閉包 func() 須要訪問局部變量 num ,雖然調用 func() 後當即返回了其結果,但
是對於 num 的引用致使優化不會發生.
相關文章
相關標籤/搜索