讓我們回顧一下箭頭函數。
箭頭函數不只是用來撰寫小東西的「速記」。它們有一些非常具體且有用的功能。
在 JavaScript 中,我們需要撰寫在其他地方執行的函數的情況很多。
例如
arr.forEach(func)
–func
由forEach
對陣列中的每個項目執行。setTimeout(func)
–func
由內建排程器執行。- …還有更多。
在 JavaScript 中,建立函數並將其傳遞到某個地方是其精神所在。
而在這些函數中,我們通常不希望離開目前的內容。這就是箭頭函數派上用場的地方。
箭頭函數沒有「this」
正如我們在章節 物件方法,「this」 中所記得的,箭頭函數沒有 this
。如果存取了 this
,它會從外部取得。
例如,我們可以使用它在物件方法中進行反覆運算
let group = {
title: "Our Group",
students: ["John", "Pete", "Alice"],
showList() {
this.students.forEach(
student => alert(this.title + ': ' + student)
);
}
};
group.showList();
在 forEach
中,使用箭頭函式,所以其中的 this.title
與外部方法 showList
中的完全相同。也就是:group.title
。
如果我們使用「一般」函式,就會發生錯誤
let group = {
title: "Our Group",
students: ["John", "Pete", "Alice"],
showList() {
this.students.forEach(function(student) {
// Error: Cannot read property 'title' of undefined
alert(this.title + ': ' + student);
});
}
};
group.showList();
錯誤發生是因為 forEach
預設以 this=undefined
執行函式,所以會嘗試存取 undefined.title
。
這不會影響箭頭函式,因為它們根本沒有 this
。
new
執行沒有 this
自然意味著另一個限制:箭頭函式無法作為建構函式使用。它們無法使用 new
呼叫。
箭頭函式 =>
與使用 .bind(this)
呼叫的一般函式之間存在細微的差異
.bind(this)
會建立函式的「繫結版本」。- 箭頭
=>
沒有建立任何繫結。函式根本沒有this
。this
的查詢方式與一般變數搜尋完全相同:在外部詞彙環境中。
箭頭沒有「引數」
箭頭函式也沒有 arguments
變數。
這對於裝飾器來說非常棒,因為我們需要使用目前的 this
和 arguments
轉發呼叫。
例如,defer(f, ms)
會取得一個函式,並回傳一個包裝函式,延遲 ms
毫秒呼叫它
function defer(f, ms) {
return function() {
setTimeout(() => f.apply(this, arguments), ms);
};
}
function sayHi(who) {
alert('Hello, ' + who);
}
let sayHiDeferred = defer(sayHi, 2000);
sayHiDeferred("John"); // Hello, John after 2 seconds
沒有箭頭函式的寫法會像這樣
function defer(f, ms) {
return function(...args) {
let ctx = this;
setTimeout(function() {
return f.apply(ctx, args);
}, ms);
};
}
這裡我們必須建立額外的變數 args
和 ctx
,以便 setTimeout
內部的函式可以取得它們。
摘要
箭頭函式
- 沒有
this
- 沒有
arguments
- 無法使用
new
呼叫 - 它們也沒有
super
,但我們還沒學到它。我們會在 類別繼承 章節中學習
這是因為它們是針對沒有自己「內容」的短程式碼而設計的,而是用於目前的內容。它們在這種使用案例中真的非常出色。
留言
<code>
標籤,要插入多行,請將它們包在<pre>
標籤中,要插入超過 10 行,請使用沙盒 (plnkr、jsbin、codepen…)