1. 程式人生 > >不能使用箭頭函式的場景

不能使用箭頭函式的場景

定義方法的時候

 ①定義字面量方法

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!'