何時不應使用es6箭頭函數

從開始接觸es6到在項目中使用已經有一段時間了,es6有不少優秀的新特性,其中最有價值的特性之一就是箭頭函數,他簡潔的語法以及更好理解的this值都很是的吸引我。可是新事物也是有兩面性的,箭頭函數有他的便捷有他的優勢,可是他也有缺點,他的優勢是代碼簡潔,this提早定義,但他的缺點也是這些,好比代碼太過簡潔,致使很差閱讀,this提早定義,致使沒法使用js進行一些es5裏面看起來很是正常的操做。針對這些缺點,下面我就總結一下什麼狀況下不應使用箭頭函數。es6

1.在對象上定義函數

先來看下面這段代碼dom

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

// Throws "TypeError: Cannot read property 'reduce' of undefined"
obj.sum();

sum方法定義在obj對象上,當調用的時候咱們發現拋出了一個TypeError,由於函數中的thiswindow對象,因此this.array也就是undefined。緣由也很簡單,相信只要瞭解過es6 箭頭函數的都知道函數

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

解決方法也很簡單,就是不用唄。這裏能夠用es6裏函數表達式的簡潔語法,在這種狀況下,this值就取決於函數的調用方式了。es5

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

obj.sum(); // => 6

經過object.method()語法調用的方法使用非箭頭函數定義,這些函數須要從調用者的做用域中獲取一個有意義的this值。prototype

2.在原型上定義函數

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

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

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

var person = new Person('wdg');

person.sayName(); // => undefined

使用function函數表達式對象

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

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

var person = new Person('wdg');

person.sayName(); // => wdg

因此給對象原型掛載方法時,使用function函數表達式繼承

3.動態上下文中的回調函數

this是js中很是強大的特色,他讓函數能夠根據其調用方式動態的改變上下文,而後箭頭函數直接在聲明時就綁定了this對象,因此再也不是動態的。
在客戶端,在dom元素上綁定事件監聽函數是很是廣泛的行爲,在dom事件被觸發時,回調函數中的this指向該dom,可當咱們使用箭頭函數時:事件

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

由於這個回調的箭頭函數是在全局上下文中被定義的,因此他的this是window。因此當this是由目標對象決定時,咱們應該使用函數表達式:

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

4.構造函數中

在構造函數中,this指向新建立的對象實例

this instanceOf MyFunction === true

須要注意的是,構造函數不能使用箭頭函數,若是這樣作會拋出異常

var Person = (name) => {
    this.name = name;
}

// Uncaught TypeError: Person is not a constructor
var person = new Person('wdg');

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

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

箭頭函數可讓語句寫的很是的簡潔,可是一個真實的項目,通常由多個開發者共同協做完成,就算由單人完成,後期也並不必定是同一我的維護,箭頭函數有時候並不會讓人很好的理解,好比

let multiply = (a, b) => b === undefined ? b => a * b : a * b;

let 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;
}

let double = multiply(2);

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

總結

毫無疑問,箭頭函數帶來了不少便利。恰當的使用箭頭函數可讓咱們避免使用早期的.bind()函數或者須要固定上下文的地方而且讓代碼更加簡潔。
箭頭函數也有一些不便利的地方。咱們在須要動態上下文的地方不能使用箭頭函數:定義須要動態上下文的函數,構造函數,須要this對象做爲目標的回調函數以及用箭頭函數難以理解的語句。在其餘狀況下,請盡情的使用箭頭函數。

相關文章
相關標籤/搜索