遇事不決箭頭函數?別期望“萬金油”語法
本文轉載自公眾號“讀芯術”(ID:AI_Discovery)
ES6箭頭函數似乎是一種很上癮的函數,一旦了解你很容易用到停不下來。作為2015年ECMAScript 6更新的一部分,箭頭函數有充分理由迅速流行。箭頭函數語法是極好的語法糖,能解決很多需求:
- 函數關鍵字
- 花括號
- return關鍵字(對于單行函數)
此外,箭頭函數還降低了JavaScript的函數范圍以及this關鍵字的部分復雜性,因為有時真正需要的只是一個匿名函數。
但事實上,箭頭函數并不一定能解決編寫JavaScript函數時的每一項需求。“萬金油”函數是奢談,下面就讓我們深入探討幾個箭頭函數不能解決的情況吧。
對象原型
先看JavaScript代碼片段:
- classRobot {
- constructor(name,catchPhrase) {
- this.name= name;
- this.catchPhrase= catchPhrase;
- }
- };
- Robot.prototype.speak= () => {
- console.log(this === window);
- return this.catchPhrase
- };
- const ironG =newRobot("Iron Giant", "Be good");
- ironG.speak();
第15行的函數調用如下:
- true
- undefined
定義了speak() 原型函數,并為新Robot對象傳遞了口號,那為什么這段代碼的計算結果是未定義的呢?
console.log()揭示了原因。如你所見,當要求控制臺判斷(this === window)時,它返回true。這為上文對象方法示例中討論的內容提供了依據。
當使用需要上下文的函數時,必須使用常規函數語法,以便使this正確綁定:
- Robot.prototype.speak=function() {
- console.log(this === ironG); // true
- return this.catchphrase;
- };
對象方法
假設想要創建一個綁定到對象的方法。
- const mario = {
- lives: 3,
- oneUp: () => {
- this.lives++;
- }
- }
這個例子中,如調用mario.oneUp(),mario.lives的值應該從3增加到4。然而,按照目前所寫的代碼,無論調用多少次oneUp(), lives的值都將保持不變。
為什么?正是因為this!
正如MDN所述:箭頭函數自身沒有this。使用了封閉詞法范圍的this值;箭頭函數遵循正常的變量查找規則。因此,當搜索當前作用域中不存在的this時,箭頭函數最終會從其封閉作用域中找到this。
例子中,封閉的范圍是window對象。調用oneUp()會要求程序增加window對象中lives的值。這樣的值不存在,所以代碼不起作用。
相反,應該使用傳統的函數語法,它將函數的this綁定到調用該函數的特定對象上:
- const mario = {
- lives: 3,
- oneUp: function() {
- this.lives++;
- }
- };
動態上下文
最后一個例子:
- const button = document.querySelector(#darkMode);
- button.addEventListener('click', () => {
- this.classList.toggle('on');
- });
到目前為止,你可能已經意識到這個代碼無效及其原因。沒錯,這又和this有關。
箭頭函數語法在函數聲明時靜態地綁定上下文,這與使用事件處理程序或事件監聽器時試圖實現的相反,它們本質上是動態的。
當通過事件處理程序或監聽器操作DOM時,觸發的事件指向屬于目標元素的this。
對于全局執行上下文中定義的箭頭函數,this將指向window。因此,上面的代碼中,this.classList將被認為是window.classList,從而導致TypeError。
從這幾個簡單的例子中可以發現,JavaScript中關于this的內容值得研究,這也許會加深你對何時使用或不使用箭頭函數的理解。




























