ES6使用箭頭函數注意點


新事物也是有兩面性的,箭頭函數有他的便捷有他的優點,但是他也有缺點,他的優點是代碼簡潔,this提前定義,但他的缺點也是這些,比如代碼太過簡潔,導致不好閱讀,this提前定義,導致無法使用JS進行一些ES5里面看起來非常正常的操作。

本質來說箭頭函數沒有自己的this,它的this是派生而來的,根據“詞法作用域”派生而來。

由於箭頭函數在調用時不會生成自身作用域下的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值一致。因為 test.sum()是在全局環境下進行調用,此時this指向全局。

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

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,但是,箭頭函數在聲明的時候就綁定了執行上下文,要動態改變上下文是不可能的,在需要動態上下文的時候它的弊端就凸顯出來:

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()函數或者需要固定上下文的地方並且讓代碼更加簡潔。

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM