箭頭函數(shù)很好用,但是不能亂用

定義字面量方法

因為箭頭函數(shù)的語法很簡潔,可能不少同學會忍不住用它來定義字面量方法,比如下面的例子

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();

定義原型方法

同樣的規(guī)則適用于原型方法(prototype method)的定義,使用箭頭函數(shù)會導致運行時的執(zhí)行上下文錯誤

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

定義事件回調(diào)函數(shù)

this 是 JS 中很強大的特性,可以通過多種方式改變函數(shù)執(zhí)行上下文,JS 內(nèi)部也有幾種不同的默認上下文指向,但普適的規(guī)則是在誰上面調(diào)用函數(shù) this 就指向誰,這樣代碼理解起來也很自然,讀起來就像在說,某個對象上正在發(fā)生某件事情。

但是,箭頭函數(shù)在聲明的時候就綁定了執(zhí)行上下文,要動態(tài)改變上下文是不可能的,在需要動態(tài)上下文的時候它的弊端就凸顯出來。比如在客戶端編程中常見的 DOM 事件回調(diào)函數(shù)(event listenner)綁定,觸發(fā)回調(diào)函數(shù)時 this 指向當前發(fā)生事件的 DOM 節(jié)點,而動態(tài)上下文這個時候就非常有用,比如下面這段代碼試圖使用箭頭函數(shù)來作事件回調(diào)函數(shù)

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

在全局上下文下定義的箭頭函數(shù)執(zhí)行時 this 會指向 window,當單擊事件發(fā)生時,瀏覽器會嘗試用 button 作為上下文來執(zhí)行事件回調(diào)函數(shù),但是箭頭函數(shù)預定義的上下文是不能被修改的,這樣 this.innerHTML 就等價于 window.innerHTML,而后者是沒有任何意義的。

定義構(gòu)造函數(shù)

構(gòu)造函數(shù)中的 this 指向新創(chuàng)建的對象,當執(zhí)行 new Car() 的時候,構(gòu)造函數(shù) Car 的上下文就是新創(chuàng)建的對象,也就是說 this instanceof Car === true。顯然,箭頭函數(shù)是不能用來做構(gòu)造函數(shù), 實際上 JS 會禁止你這么做,如果你這么做了,它就會拋出異常。

換句話說,箭頭構(gòu)造函數(shù)的執(zhí)行并沒有任何意義,并且是有歧義的

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

追求過短的代碼

箭頭函數(shù)允許你省略參數(shù)兩邊的括號、函數(shù)體的花括號、甚至 return 關鍵詞,這對編寫更簡短的代碼非常有幫助。這讓我想起大學計算機老師給學生留過的有趣作業(yè):看誰能使用 C 語言編寫出最短的函數(shù)來計算字符串的長度,這對學習和探索新語言特性是個不錯的法子。但是,在實際的軟件工程中,代碼寫完之后會被很多工程師閱讀,真正的 write once, read many times,在代碼可讀性方面,最短的代碼可能并不總是最好的。一定程度上,壓縮了太多邏輯的簡短代碼,閱讀起來就沒有那么直觀

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

multiply 函數(shù)會返回兩個數(shù)字的乘積或者返回一個可以繼續(xù)調(diào)用的固定了一個參數(shù)的函數(shù)。代碼看起來很簡短,但大多數(shù)人第一眼看上去可能無法立即搞清楚它干了什么,怎么讓這段代碼可讀性更高呢?有很多辦法,可以在箭頭函數(shù)中加上括號、條件判斷、返回語句,或者使用普通的函數(shù)

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

為了讓代碼可讀性更高,在簡短和啰嗦之間把握好平衡是非常有必要的。

總結(jié)

箭頭函數(shù)無疑是 ES6 帶來的重大改進,在正確的場合使用箭頭函數(shù)能讓代碼變的簡潔、短小,但某些方面的優(yōu)勢在另外一些方面可能就變成了劣勢,在需要動態(tài)上下文的場景中使用箭頭函數(shù)你要格外的小心,這些場景包括:定義對象方法、定義原型方法、定義構(gòu)造函數(shù)、定義事件回調(diào)函數(shù)。

轉(zhuǎn)自:知乎專欄 https://zhuanlan.zhihu.com/p/26540168

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容