者:Dmitri Pavlutin譯者:前端小智 來源:dmitripavlutin.com
箭頭功能值得流行。它的語法簡潔明了,使用詞法綁定綁定 this,它非常適合作為回調。在本文中,通過了解決學習5個最佳實踐,以便我們可以從中學習更多箭頭函數的知識,并從它身上獲得更多的好處。
JS 中的箭頭函數是匿名(anonymous)的:函數的name屬性是''。
(?number?=>?number?+?1?).name;?//?=>?''
在調試會話或調用堆棧分析期間,匿名函數被標記為anonymous。不幸的是,anonymous程序不提供有關正在執行的代碼的任何線索。
這里是執行匿名函數的代碼的調試會話:
右邊的調用堆棧由兩個標記為anonymous的函數組成,我們無法從這樣的調用堆棧信息中獲得任何有用的信息。
幸運的是,函數名推斷(ES2015的功能)可以在某些條件下檢測到函數名稱。名稱推斷的思想是JS 可以從其語法位置確定箭頭函數名稱:從保存函數對象的變量名稱中獲取。
我們來看看函數名稱推斷的工作原理:
const?increaseNumber?=?number?=>?number?+?1;
increaseNumber.name;?//?=>?'increaseNumber'
因為變量increaseNumber保存了箭頭函數,所以 JS 決定使用increaseNumber作為該函數的名稱。因此,箭頭函數的名稱為 'increaseNumber'。
第1個實踐:
一個好的做法是使用函數名稱推斷來命名箭頭函數。
現在我們用使用名稱推斷的代碼檢查一個調試會話:
因為箭頭函數有名稱,所以調用堆棧提供了有關正在執行的代碼的更多信息。
內聯函數是僅具有一個表達式的函數。我喜歡箭頭功能,可以編寫短內聯函數。
例如,不要使用箭頭函數的長形式:
const?array?=?[1,?2,?3];
array.map((number)?=>?{?
??return?number?*?2;
});
當箭頭函數只有一個表達式時,可以輕松地刪除大括號{}和return語句:
const?array?=?[1,?2,?3];
array.map(number?=>?number?*?2);
第2個實踐:
當函數只有一個表達式時,一個好的做法是使用內聯箭頭函數格式
比較操作符>、<、<=和>=看起來類似于f胖箭頭=>(它定義了箭頭函數)。當在內聯箭頭函數中使用這些比較操作符時,會產生一些混淆。
例如我們定義一個使用<=操作符的箭頭函數
const?negativeToZero?=?number?=>?number?<=?0???0?:?number;
同一行上的兩個符號=>和<=的存在會引起誤解。
為了清楚地將胖箭頭與比較操作符區分開,我們可以使用圓括號:
const?negativeToZero?=?number?=>?(number?<=?0???0?:?number);
第二個選項是使用更長的形式來定義箭頭函數:
const?negativeToZero?=?number?=>?{
??return?number?<=?0???0?:?number;
};
這些重構消除了胖箭頭符號和比較操作符之間的混淆。
第3個實踐:
如果箭頭函數包含操作符>、<、<=和>=,一個好的做法是將表達式包裝成一對括號,或者故意使用更長的箭頭函數形式。
在內聯箭頭函數中使用對象字面量會觸發語法錯誤:
const?array?=?[1,?2,?3];
//?throws?SyntaxError!
array.map(number?=>?{?'number':?number?});
JS 認為花括號是代碼塊,而不是對象文字。
將對象字面量加上一對括號即可解決此問題:
const?array?=?[1,?2,?3];
//?Works!
array.map(number?=>?({?'number':?number?}));
如果對象字面量有很多屬性,我們可以使用換行,同時仍然保持箭頭函數內聯
const?array?=?[1,?2,?3];
//?Works!
array.map(number?=>?({
??'number':?number
??'propA':?'value?A',
??'propB':?'value?B'
}));
第4個實踐:
在內聯箭頭函數中使用對象時,把改對象包裝在一對括號中。
箭頭函數的語法很短,很好。但是,副作用是,當許多箭頭函數嵌套時,它可能是晦澀難懂。
我們考慮以下情況。單擊按鈕后,啟動對服務器的請求,響應準備就緒后,將各項記錄到控制臺:
myButton.addEventListener('click',?()?=>?{
??fetch('/items.json')
????.then(response?=>?response.json());
????.then(json?=>?{
??????json.forEach(item?=>?{
????????console.log(item.name);
??????});
????});
});
這里有三層箭頭函數的嵌套,需要花時間和精力來了解代碼的作用。
為了提高嵌套函數的可讀性,第一種方法是引入每個包含箭頭函數的變量,該變量應簡明地描述函數的功能。
const?readItemsJson?=?json?=>?{
??json.forEach(item?=>?console.log(item.name));
};
const?handleButtonClick?=?()?=>?{
??fetch('/items.json')
????.then(response?=>?response.json());
????.then(readItemsJson);
};
myButton.addEventListener('click',?handleButtonClick);
重構將箭頭函數提取到變量readItemsJson和handleButtonClick中。嵌套級別從3減少到2。現在,我們可以更輕松地了解腳本的功能。
更好的是,可以使用async/await語法重構整個函數,這是解決函數嵌套的一個很好的方法:
const?handleButtonClick?=?async?()?=>?{
??const?response?=?await?fetch('/items.json');
??const?json?=?await?response.json();
??json.forEach(item?=>?console.log(item.name));
};
myButton.addEventListener('click',?handleButtonClick);
第5個實踐:
避免箭頭函數過多的嵌套,好的做法是通過將箭頭函數提取為獨立函數,或者盡可能使用async/await語法。
JS中的箭頭函數是匿名的。為了使調試更高效,一個好的實踐是使用變量來保存箭頭函數,這允許JS 推斷函數名。
當函數主體具有一個表達式時,嵌入式箭頭函數非常方便。
操作符>、<、<=和>=看起來類似于胖箭頭=>,在內聯箭頭函數中使用這些操作符時必須小心。
對象字面量語法{prop:'value'}與代碼塊{}相似。因此,當將對象字面量放置在嵌入式箭頭函數中時,需要將其包裝在一對括號中:()=>({prop:'value'})。
最后,函數的過度嵌套模糊了代碼意圖。減少箭頭函數嵌套的一個好方法是將它們提取到變量中。或者,嘗試使用更好的特性,如async/await語法。
對于箭頭函數,你還有什么建議,歡迎留言討論。
原文:https://dmitripavlutin.com/javascript-arrow-functions-best-practices/
ES6標準新增了一種新的函數:Arrow Function(箭頭函數)。為什么叫Arrow Function?
因為它的定義用的就是一個箭頭:
x => x * x
示例相當于如下代碼:
function (x) {
return x * x;
}
JavaScript箭頭函數是ECMAScript 6中引入的編寫函數表達式的一種簡便方法。
箭頭函數的語法如下:
(parameters) => { statements }
如果沒有參數,則表示一個箭頭函數,如下所示:
() => { statements }
當您只有一個參數時,左括號是可選的:
parameters => { statements }
如果包含只返回返回表達式,請刪除方括號:
parameters => expression
簡潔的語法
讓我們看一下常規函數:
function funcName(params) {
return params + 2;
}
funcName(2); // 4
然后通過箭頭函數精簡之后為:
var funcName=params => params+2;
funcName(2); // 4
可以看到通過箭頭函數實現之后,語法更加精簡。
不綁定this
與常規函數不同,箭頭函數不綁定this。相反,它是在詞匯上綁定的(即this保持其原始上下文的含義)。
由于JavaScript函數對this綁定的錯誤處理,下面的例子無法得到預期結果:
var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = function () {
return 2020 - this.birth; // this指向window或undefined
};
return fn();
}
};
但是,箭頭函數完全修復了this的指向,this總是指向詞法作用域,也就是外層調用者obj:
var obj = {
birth: 1990,
getAge: function () {
var b = this.birth; // 1990
var fn = () => 2020 - this.birth; // this指向obj對象
return fn();
}
};
obj.getAge(); // 30
應用箭頭函數時要注意的一些限制條件:
如果你嘗試使用箭頭函數作為構造函數,那么你會得到異常。請看下面的代碼:
var foo = (name, age) => { name = name, age = age };
var f1 = new foo("cat", 6);
代碼試圖通過使用箭頭函數foo作為構造函數來創建對象f1,JavaScript將拋出以下異常:
而且,當你試圖輸出箭頭函數的原型值時,你會得到undefined的輸出:
var foo = (name, age) => { name = name, age = age };
console.log(foo.prototype);
發生這種情況的原因是因為箭頭函數沒有原型屬性。請記住:雖然箭頭函數為你提供了編寫函數表達式的簡短方法,但它沒有自己的this值,也不能用作構造函數。
n2=n+1
在markdown中寫法:
n<sup>2</sup>=n+1
a=log2b
在markdown中寫法:
a=log<sub>2</sub>b
? ? ° ? ? ? ? √ " &
在markdown中寫法:
? ? ° ? ? ? ? √ \" \&
居中::-:
箭頭符號:
在markdown中寫法:
$\Rightarrow$ $\Leftarrow$
在 Markdown 文檔中,可以直接采用 HTML 標記插入空格(blank space),而且無需任何其他前綴或分隔符。具體如下所示:
插入一個空格 或 或 (non-breaking space)
插入兩個空格 ?或?或?(en space)
插入四個空格 ?或?或?(em space)
插入細的空格 ?或?或?(thin space)
在markdown中寫法:
插入一個空格
或 或
插入兩個空格
?或?或?
插入四個空格
?或?或?
插入細的空格
?或?或?
注意:不要漏掉分號。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。