不能使用箭頭函式的場景
定義方法的時候
①定義字面量方法
const calculator = { array: [1, 2, 3], sum: () => { console.log(this === window); // => true return this.array.reduce((result, item) => result + item); } }; console.log(this === window); // => true // Throws "TypeError: Cannot read property 'reduce' of undefined" calculator.sum();
calculator.sum 使用箭頭函式來定義,但是呼叫的時候會丟擲 TypeError,因為執行時 this.array 是未定義的,呼叫 calculator.sum 的時候,執行上下文裡面的 this 仍然指向的是 window,原因是箭頭函式把函式上下文繫結到了 window 上,this.array 等價於 window.array,顯然後者是未定義的。
解決方法
const calculator = { array: [1, 2, 3], sum() { console.log(this === calculator); // => true return this.array.reduce((result, item) => result + item); } }; calculator.sum(); // => 6
②定義原型方法
function Cat(name) {
this.name = name;
}
Cat.prototype.sayCatName = () => {
console.log(this === window); // => true
return this.name;
};
const cat = new Cat('Mew');
cat.sayCatName(); // => undefined
使用傳統的函式表示式就能解決問題 JS Bin:
function Cat(name) { this.name = name; } Cat.prototype.sayCatName = function () { console.log(this === cat); // => true return this.name; }; const cat = new Cat('Mew'); cat.sayCatName(); // => 'Mew'
sayCatName 變成普通函式之後,被呼叫時的執行上下文就會指向新建立的 cat 例項。
定義事件回撥函式
,箭頭函式在宣告的時候就綁定了執行上下文,要動態改變上下文是不可能的,在需要動態上下文的時候它的弊端就凸顯出來。比如在客戶端程式設計中常見的 DOM 事件回撥函式(event listenner)繫結,觸發回撥函式時 this 指向當前發生事件的 DOM 節點,而動態上下文這個時候就非常有用,比如下面這段程式碼試圖使用箭頭函式來作事件回撥函式
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log(this === window); // => true
this.innerHTML = 'Clicked button';
});
在全域性上下文下定義的箭頭函式執行時 this 會指向 window,當單擊事件發生時,瀏覽器會嘗試用 button 作為上下文來執行事件回撥函式,但是箭頭函式預定義的上下文是不能被修改的,這樣 this.innerHTML 就等價於 window.innerHTML,而後者是沒有任何意義的。
使用函式表示式就可以在執行時動態的改變 this,修正後的程式碼
const button = document.getElementById('myButton');
button.addEventListener('click', function() {
console.log(this === button); // => true
this.innerHTML = 'Clicked button';
});
定義建構函式
建構函式中的 this 指向新建立的物件,當執行 new Car() 的時候,建構函式 Car 的上下文就是新建立的物件,也就是說 this instanceof Car === true。顯然,箭頭函式是不能用來做建構函式, 實際上 JS 會禁止你這麼做,如果你這麼做了,它就會丟擲異常。
換句話說,箭頭建構函式的執行並沒有任何意義,並且是有歧義的。比如,當我們執行下面的程式碼 JS Bin:
const Message = (text) => {
this.text = text;
};
// Throws "TypeError: Message is not a constructor"
const helloMessage = new Message('Hello World!');
構造新的 Message 例項時,JS 引擎拋了錯誤,因為 Message 不是建構函式。在筆者看來,相比舊的 JS 引擎在出錯時悄悄失敗的設計,ES6 在出錯時給出具體錯誤訊息是非常不錯的實踐。可以通過使用函式表示式或者函式宣告 來宣告建構函式修復上面的例子 JS Bin:
const Message = function(text) {
this.text = text;
};
const helloMessage = new Message('Hello World!');
console.log(helloMessage.text); // => 'Hello World!'