本文主要總結ES6新增的函式的用法及注意點。
函式引數預設值
ES6允許為函式引數設定預設值。用法如下:
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello
複製程式碼
這樣寫的好處是:
- 比ES5寫法簡潔
- 便於閱讀程式碼
- 有利於程式碼優化
需要注意的點:
- 引數變數是預設宣告的,所以不能用let和const再次宣告。但是var是可以的。
- 使用引數預設值時,函式不能有同名引數。
- 引數預設值是惰性求值的。
- 有預設值的引數最好放到後面,如果放到前面,傳參無法省略;若要使用預設值,需要顯示傳undefined才會觸發預設值
- 函式的length屬性返回沒有指定預設值的引數個數。而且如果設定的預設值不是尾引數,那麼length屬性不再計入後面的引數。
(function (a) {}).length // 1
(function (a = 5) {}).length // 0
(function (a, b, c = 5) {}).length // 2
(function (a = 0, b, c) {}).length // 0
(function (a, b = 1, c) {}).length // 1
複製程式碼
rest引數
rest引數的引入,用於獲取函式的多餘引數,這樣就不需要使用arguments物件了。
function push(array, ...items) {
items.forEach(function(item) {
array.push(item);
console.log(item);
});
}
var a = [];
push(a, 1, 2, 3)
複製程式碼
需要注意的點:
- rest 引數之後不能再有其他引數(即只能是最後一個引數),否則會報錯。
- 函式的length屬性,不包括 rest 引數。
嚴格模式
ES6規定只要函式引數使用了預設值、解構賦值或者擴充套件運算子,那麼函式內部就不能顯示設定為嚴格模式,否則報錯。 解決方案:
- 設定全域性性的嚴格模式
'use strict';
function doSomething(a, b = a) {
// code
}
複製程式碼
- 把函式包裹在一個無引數的立即執行函式裡
const doSomething = (function () {
'use strict';
return function(value = 42) {
return value;
};
}());
複製程式碼
name屬性
函式的那麼屬性,返回函式的函式名。 需要注意的點:
- 將匿名函式賦值給一個變數,ES5的name屬性返回空字串,ES6的name屬性返回實際的函式名。
var f = function () {};
// ES5
f.name // ""
// ES6
f.name // "f"
複製程式碼
- Function建構函式返回的函式例項,name屬性的值為anonymous。
(new Function).name // "anonymous"
複製程式碼
- bind返回的函式,name屬性值會加上bound字首。
function foo() {};
foo.bind({}).name // "bound foo"
(function(){}).bind({}).name // "bound "
複製程式碼
箭頭函式
用法很簡單,主要記錄一下需要注意的點。
- 如果箭頭函式直接返回一個物件,必須在物件外面加上括號,否則會報錯。
// 報錯
let getTempItem = id => { id: id, name: "Temp" };
// 不報錯
let getTempItem = id => ({ id: id, name: "Temp" });
複製程式碼
- 函式體內的this物件,就是定義時所在的物件,而不是使用時所在的物件。
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}
var id = 21;
foo.call({ id: 42 });
// id: 42
複製程式碼
箭頭函式的這個特點,使得this指向固定化。根本原因是箭頭函式根本沒有自己的this,導致內部的this就是外層程式碼的this。
- 不可以當做建構函式使用,即不可以使用new命令,否則會丟擲錯誤。因為箭頭函式實際上沒有this!!!
- 不可以使用arguments物件,在箭頭函式內部該物件不存在。如果要用,可以使用rest引數代替。
- 不可以使用yield命令,因此箭頭函式不能用作Generator函式。
- 箭頭函式內部不存在arguments、super、new.target物件
尾呼叫優化
尾呼叫指的是某個函式的最後一步是呼叫另一個函式。尾呼叫不一定出現在函式尾部,只要是最後一步操作即可。
function f(x) {
if (x > 0) {
return m(x)
}
return n(x);
}
複製程式碼
上面就是一個尾呼叫的例子。 同時,下面的幾種情況不是尾呼叫。
// 情況一
function f(x){
let y = g(x);
return y;
}
// 情況二
function f(x){
return g(x) + 1;
}
// 情況三
function f(x){
g(x);
}
複製程式碼
由於函式內部呼叫另一個函式,會形成一個呼叫棧。而尾呼叫是函式的最後一步操作,所以尾呼叫的時候不需要保留外層函式的呼叫幀。直接用內層函式的呼叫幀就可以。這就是尾呼叫優化。
由此可知,我們把函式都寫成尾呼叫,使得每次執行時,呼叫幀只有一項,這會大大節省記憶體。
但是需要注意一點:
- 只有不再用到外層函式的內部變數,內層函式的呼叫幀才會取代外層函式的呼叫幀,否則無法進行尾呼叫優化。
- 尾遞迴優化和它類似。
- ES6的尾呼叫優化只在嚴格模式下開啟,正常模式無效。