ES6使用箭頭函數注意點

新事物也是有兩面性的,箭頭函數有他的便捷有他的優勢,可是他也有缺點,他的優勢是代碼簡潔,this提早定義,但他的缺點也是這些,好比代碼太過簡潔,致使很差閱讀,this提早定義,致使沒法使用JS進行一些ES5裏面看起來很是正常的操做。javascript

本質來講箭頭函數沒有本身的this,它的this是派生而來的,根據「詞法做用域」派生而來。java

因爲箭頭函數在調用時不會生成自身做用域下的thisarguments值,其持有外部包含它的函數的this值,而且在調用的時候就定下來了,不可動態改變,下面我就總結一下什麼狀況下不應使用箭頭函數。函數

在對象上定義函數

const test = {
    array: [1, 2, 3],
    sum: () => {
        console.log(this === window); // => true
        return this.array.reduce((result, item) => result + item);
    }
};
test.sum();
// TypeError: Cannot read property 'reduce' of undefined

緣由就是,箭頭函數沒有它本身的this值,箭頭函數內的this值繼承自外圍做用域。this

對象方法內的this指向調用這個方法的對象,若是使用箭頭函數,this和對象方法在調用的時候所處環境的this值一致。由於 test.sum()是在全局環境下進行調用,此時this指向全局。prototype

解決方法也很簡單,使用函數表達式或者方法簡寫(ES6 中已經支持)來定義方法,這樣能確保 this 是在運行時是由包含它的上下文決定的。code

const test = {
    array: [1, 2, 3],
    sum() {
        console.log(this === test); // => true
        return this.array.reduce((result, item) => result + item);
    }
};
test.sum();
// 6

定義原型方法

在對象原型上定義函數也是遵循着同樣的規則對象

function Person(name) {
    this.name = name;
}

Person.prototype.sayName = () => {
    console.log(this === window); // => true
    return this.name;
};

const cat = new Person('Mew');
cat.sayName(); // => undefined

使用傳統的函數表達式就能解決問題繼承

function Person(name) {
    this.name = name;
}

Person.prototype.sayName = function() {
    console.log(this === Person); // => true
    return this.name;
};

const cat = new Person('Mew');
cat.sayName(); // => Mew

定義事件回調函數

thisJS中很是強大的特色,他讓函數能夠根據其調用方式動態的改變上下文,而後箭頭函數直接在聲明時就綁定了this對象,因此再也不是動態的。事件

在客戶端,在DOM元素上綁定事件監聽函數是很是廣泛的行爲,在DOM事件被觸發時,回調函數中的this指向該DOM,可是,箭頭函數在聲明的時候就綁定了執行上下文,要動態改變上下文是不可能的,在須要動態上下文的時候它的弊端就凸顯出來:ip

const button = document.getElementById('myButton');
button.addEventListener('click', () => {
    console.log(this === window); // => true
    this.innerHTML = 'Clicked button';
});

由於這個回調的箭頭函數是在全局上下文中被定義的,因此他的thiswindow。換句話說就是,箭頭函數預約義的上下文是不能被修改的,這樣 this.innerHTML 就等價於 window.innerHTML,然後者是沒有任何意義的。

使用函數表達式就能夠在運行時動態的改變 this

const button = document.getElementById('myButton');
button.addEventListener('click', function() {
    console.log(this === button); // => true
    this.innerHTML = 'Clicked button';
});

定義構造函數

若是使用箭頭函數會報錯。

顯然,箭頭函數是不能用來作構造函數。

const Message = (text) => {
    this.text = text;
};
const helloMessage = new Message('Hello World!');
// Throws "TypeError: Message is not a constructor"

理論上來講也是不能這麼作的,由於箭頭函數在建立時this對象就綁定了,更不會指向對象實例。

太簡短的(難以理解)函數

箭頭函數可讓語句寫的很是的簡潔,可是一個真實的項目,通常由多個開發者共同協做完成,箭頭函數有時候並不會讓人很好的理解:

const multiply = (a, b) => b === undefined ? b => a * b : a * b;
const double = multiply(2);
double(3); // => 6
multiply(2, 3); // => 6

代碼看起來很簡短,但大多數人第一眼看上去可能沒法當即搞清楚它幹了什麼。

這個函數的做用就是當只有一個參數a時,返回接受一個參數b返回a*b的函數,接收兩個參數時直接返回乘積。

爲了讓這個函數更好的讓人理解,咱們能夠爲這個箭頭函數加一對花括號,並加上return語句,或者直接使用函數表達式:

function multiply(a, b) {
    if (b === undefined) {
        return function(b) {
            return a * b;
        }
    }
    return a * b;
}

const double = multiply(2);
double(3); // => 6
multiply(2, 3); // => 6

毫無疑問,箭頭函數帶來了不少便利。恰當的使用箭頭函數可讓咱們避免使用早期的.bind()函數或者須要固定上下文的地方而且讓代碼更加簡潔。

箭頭函數也有一些不便利的地方。咱們在須要動態上下文的地方不能使用箭頭函數:定義對象方法、定義原型方法、定義構造函數、定義事件回調函數。在其餘狀況下,請盡情的使用箭頭函數。

相關文章
相關標籤/搜索