[譯]JS箭頭函數(shù)三連問(wèn):為何用宰译、怎么用、何時(shí)用

[譯]JS箭頭函數(shù)三連問(wèn):為何用魄懂、怎么用沿侈、何時(shí)用
在現(xiàn)代JS中最讓人期待的特性就是關(guān)于箭頭函數(shù),用=>來(lái)標(biāo)識(shí)市栗。箭頭函數(shù)有兩個(gè)主要的優(yōu)點(diǎn):其一是非常簡(jiǎn)明的語(yǔ)法缀拭,另外就是直觀的作用域和this的綁定。

因?yàn)檫@些優(yōu)點(diǎn)填帽,箭頭函數(shù)比起其他形式的函數(shù)聲明更加受歡迎蛛淋。比如,受歡迎的airbnb eslint configuration庫(kù)會(huì)強(qiáng)制使用JavaScript箭頭函數(shù)創(chuàng)建匿名函數(shù)篡腌。

然而褐荷,就像世間萬(wàn)物一樣,箭頭函數(shù)有一些優(yōu)點(diǎn)也有一些“缺點(diǎn)”嘹悼,這就需要在使用的時(shí)候做一些權(quán)衡了叛甫。

學(xué)習(xí)如何權(quán)衡是使用好箭頭函數(shù)的關(guān)鍵。在這篇文章中我們將回顧箭頭函數(shù)是怎樣工作的杨伙,然后深入探討其监,實(shí)際代碼中箭頭函數(shù)是如何改進(jìn)我們代碼的,以及一些箭頭函數(shù)不推薦的情況限匣。

什么才是箭頭函數(shù)
JS的箭頭函數(shù)大概就像python中的lambda(python定義匿名函數(shù)的關(guān)鍵字)和ruby中的blocks(類似于閉包)一樣抖苦。 這些匿名函數(shù)都有他們特殊的語(yǔ)法:首先接收一定數(shù)目的參數(shù),然后在定義它們的函數(shù)的作用域或就近作用域中執(zhí)行膛腐。

接下來(lái)我們將詳細(xì)探討這些睛约。

箭頭函數(shù)的語(yǔ)法
箭頭函數(shù)有一個(gè)大體的結(jié)構(gòu),同時(shí)也有很多的特殊情況可以簡(jiǎn)化哲身。 核心的結(jié)構(gòu)如下:

(argument1, argument2, ... argumentN) => {
    // function body
}

在括號(hào)里面有一系列的參數(shù)辩涝,接著跟著一個(gè)箭頭符號(hào)=>,最后是函數(shù)體勘天。這跟傳統(tǒng)的函數(shù)很相像怔揩,只是我們省略了function關(guān)鍵字,并且添加了一個(gè)=>在參數(shù)后面脯丝。

并且商膊,這里也有很多種情況,讓箭頭函數(shù)結(jié)構(gòu)變得更加的簡(jiǎn)潔宠进。

首先晕拆,如果函數(shù)體里面是一個(gè)單獨(dú)的表達(dá)式,你可以省略大括號(hào)直接將表達(dá)式寫在一行材蹬,并且表達(dá)式的結(jié)果也將會(huì)被函數(shù)直接返回实幕。比如:

const add = (a, b) => a + b;

其次吝镣,如果這傳入的是一個(gè)單獨(dú)的參數(shù),你也可省略參數(shù)部分的括號(hào)昆庇。比如:

const getFirst = array => array[0];

如你所見末贾,這樣就看起來(lái)更加的簡(jiǎn)潔了,我們也將在后面說(shuō)明更多的特性整吆。

高級(jí)語(yǔ)法
如果你了解這些高級(jí)語(yǔ)法之后將十分受用拱撵。

首先,如果你嘗試在一行書寫函數(shù)表蝙,但是返回的值卻是一個(gè)對(duì)象內(nèi)容拴测,你原想這樣寫:

(name, description) => {name: name, description: description};

而問(wèn)題就是這樣的語(yǔ)法會(huì)引起歧義,會(huì)誤以為你在寫一個(gè)函數(shù)的函數(shù)體勇哗。 如果想返回的是單個(gè)的對(duì)象昼扛,請(qǐng)用括號(hào)包裝該對(duì)象:

(name, description) => ({name: name, description: description});

封閉的上下文作用域
不像其他形式的函數(shù),箭頭函數(shù)并沒有他們自己的執(zhí)行上下文欲诺。實(shí)際上抄谐,這就意味著代碼中的this和arguments都是繼承自他們的父函數(shù)。

比如扰法,比較下面箭頭函數(shù)和傳統(tǒng)函數(shù)的區(qū)別:

const test = {
  name: 'test object',
  createAnonFunction: function() {
    return function() {
      console.log(this.name);
      console.log(arguments);
    };
  },
  createArrowFunction: function() {
    return () => {
      console.log(this.name);
      console.log(arguments);
    };
  }
};

我們有一個(gè)有兩個(gè)方法的對(duì)象蛹含,每個(gè)方法都返回了一個(gè)匿名函數(shù)。區(qū)別在于第一個(gè)方法里面用了傳統(tǒng)的函數(shù)表達(dá)式塞颁,后面的用了箭頭函數(shù)表達(dá)式浦箱。如果我們?cè)趥魅胪瑯拥膮?shù)運(yùn)行,我們得到了兩個(gè)不同的結(jié)果祠锣。

const anon = test.createAnonFunction('hello', 'world');
//返回匿名函數(shù)
const arrow = test.createArrowFunction('hello', 'world');
anon();
//undefined
//{}
// this->window
arrow();
//test object
//object { '0': 'hello', '1': 'world' }
//this->test

第一個(gè)匿名函數(shù)有自己的上下文(指向并非test對(duì)象)酷窥,當(dāng)你調(diào)用的時(shí)候沒有參考的this.name的屬性,(注意:現(xiàn)在this指向window)伴网,也沒有創(chuàng)建它時(shí)調(diào)用的參數(shù)蓬推。另一個(gè),箭頭函數(shù)與創(chuàng)建它的函數(shù)有相同的上下文澡腾,讓其可以訪問(wèn)參數(shù)arguments和對(duì)象沸伏。

箭頭函數(shù)改進(jìn)您的代碼
傳統(tǒng)lambda函數(shù)的主要用例之一,就是將函數(shù)用于數(shù)組的遍歷动分,現(xiàn)在用JavaScript箭頭函數(shù)實(shí)現(xiàn)毅糟。 比如你有一個(gè)有值的數(shù)組,你想去map遍歷每一項(xiàng)澜公,這時(shí)箭頭函數(shù)是非常推薦的:

const words = ['hello', 'WORLD', 'Whatever'];
const downcasedWords = words.map(word => word.toLowerCase());

一個(gè)及其常見的例子就是返回一個(gè)對(duì)象的某個(gè)值:

const names = objects.map(object => object.name);

類似的姆另,當(dāng)用forEach來(lái)替換傳統(tǒng)for循環(huán)的時(shí)候,實(shí)際上箭頭函數(shù)會(huì)直觀的保持this來(lái)自于父一級(jí)

this.examples.forEach(example => {
  this.runExample(example);
});

Promise和Promise鏈
當(dāng)在編寫異步程序的時(shí)候,箭頭函數(shù)也會(huì)讓代碼更加直觀和簡(jiǎn)潔蜕青。

Promise可以更簡(jiǎn)單的編寫異步程序苟蹈。雖然你樂意去使用async/await糊渊,你也需要好好理解promise,因?yàn)檫@是他們的基礎(chǔ)右核。

使用promise,仍然需要定義你的代碼執(zhí)行完成之后的回調(diào)函數(shù)渺绒。 這是箭頭函數(shù)的理想位置贺喝,特別是如果您生成的函數(shù)是有狀態(tài)的,同時(shí)想引用對(duì)象中的某些內(nèi)容宗兼。

this.doSomethingAsync().then((result) => {
  this.storeResult(result);
});

對(duì)象轉(zhuǎn)換
箭頭函數(shù)的另一個(gè)常見而且十分有用的地方就是用于封裝的對(duì)象轉(zhuǎn)換躏鱼。 例如在Vue.js中,有一種通用模式殷绍,就是使用mapState將Vuex存儲(chǔ)的各個(gè)部分染苛,直接包含到Vue組件中。 這涉及到定義一套mappers主到,用于從原對(duì)象到完整的轉(zhuǎn)換輸出茶行,這在組件問(wèn)題中實(shí)十分有必要的。 這一系列簡(jiǎn)單的轉(zhuǎn)換,使用箭頭函數(shù)是最合適不過(guò)的登钥。比如:

export default {
  computed: {
    ...mapState({
      results: state => state.results,
      users: state => state.users,
    });
  }
}

你不應(yīng)該使用箭頭函數(shù)的情景
這里有許多箭頭函數(shù)不推薦的場(chǎng)景畔师,這種情況之下不僅沒有幫助,而且還會(huì)造成不必要的麻煩牧牢。

首先就是對(duì)象中的方法看锉。這里有一個(gè)函數(shù)上下文的例子,對(duì)于我們理解很有幫助塔鳍。 曾經(jīng)流行一種趨勢(shì)伯铣,用class類的語(yǔ)法和箭頭函數(shù),為其自動(dòng)綁定方法轮纫。比如:事件方法可以使用腔寡,但是仍然綁定在class類中。 看起來(lái)就像下面的例子:

class Counter {
  counter = 0;
  handleClick = () => {
    this.counter++;
  }
}

在這種方法中,如果被一個(gè)點(diǎn)擊事件函數(shù)調(diào)用了蜡感,它雖然不是Counter的上下文中蹬蚁,它仍舊可以訪問(wèn)實(shí)例的數(shù)據(jù),這種方式的缺點(diǎn)不言而喻郑兴。

用這種方式的確提供了一種綁定函數(shù)的快捷方式犀斋,但是函數(shù)的表達(dá)形式多種多樣,相當(dāng)不直觀情连。如果你嘗試在原型使用這種對(duì)象叽粹,這將不利于測(cè)試,同時(shí)也會(huì)產(chǎn)生很多問(wèn)題。 相反虫几,推薦用一種常規(guī)的綁定方式锤灿,如有必要可以綁定在實(shí)例的構(gòu)造函數(shù)中:

class Counter {
  counter = 0;
  handleClick() {
    this.counter++;
  }
  constructor() {
    this.handleClick = this.handleClick.bind(this);
  }
}

深層調(diào)用
另一種使用箭頭函數(shù)會(huì)讓你頭疼的地方,就是你去用很多函數(shù)的組合調(diào)用辆脸,尤其是函數(shù)的深層調(diào)用但校。 簡(jiǎn)單的理由跟匿名函數(shù)一樣,堆棧的追蹤很復(fù)雜啡氢。

如果你的函數(shù)僅僅在一層之下状囱,而不是深層的迭代,這倒不是什么問(wèn)題倘是。但是如果你將函數(shù)定義為箭頭函數(shù)亭枷,并且在他們之間來(lái)回調(diào)用,當(dāng)你調(diào)試bug的時(shí)候你將被代碼困惑搀崭,甚至得到如下的錯(cuò)誤信息:

{anonymous}()
{anonymous}()
{anonymous}()
{anonymous}()
{anonymous}()
//anonymous 匿名

有動(dòng)態(tài)上下文的函數(shù)
還有最有一種箭頭函數(shù)會(huì)讓你困惑的情形叨粘,就是this是動(dòng)態(tài)綁定的時(shí)候。 如果你在以下情形使用箭頭函數(shù)瘤睹,那么this的動(dòng)態(tài)綁定不會(huì)如期工作升敲,并且你也會(huì)困惑這些代碼為什么不像預(yù)期那樣工作,也會(huì)給你之后工作的人造成麻煩默蚌。 一些典型的例子:

事件的調(diào)用函數(shù)冻晤,this指向當(dāng)前的目標(biāo)屬性
在jquery中,大多數(shù)時(shí)候this指向的是當(dāng)前被選擇的元素
在vue中绸吸,methods和computed中的this指向的是vue的組件鼻弧。
當(dāng)然你也可以在上面的情形之下謹(jǐn)慎的使用箭頭函數(shù)。但特別是在jquery和vue的情況下, 這通常會(huì)干擾正常功能, 并使您感到困惑:為什么看起來(lái)跟別人代碼一樣的代碼就是不工作锦茁。

總結(jié)
箭頭函數(shù)是JS語(yǔ)言中十分特別的屬性攘轩,并且使很多情形中代碼更加的變化莫測(cè)。盡管如此码俩,就像其他的語(yǔ)言特性度帮,他們有各自的優(yōu)缺點(diǎn)。因此我們使用它應(yīng)該僅僅是作為一種工具稿存,而不是無(wú)腦的簡(jiǎn)單的全部替換為箭頭函數(shù)笨篷。

原文:https://juejin.im/post/5be599d4e51d451d23633ec8z

精彩稍后繼續(xù),盡請(qǐng)點(diǎn)贊打賞.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瓣履,隨后出現(xiàn)的幾起案子率翅,更是在濱河造成了極大的恐慌,老刑警劉巖袖迎,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冕臭,死亡現(xiàn)場(chǎng)離奇詭異腺晾,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)辜贵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門悯蝉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人托慨,你說(shuō)我怎么就攤上這事鼻由。” “怎么了榴芳?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵嗡靡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我窟感,道長(zhǎng),這世上最難降的妖魔是什么歉井? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任柿祈,我火速辦了婚禮,結(jié)果婚禮上哩至,老公的妹妹穿的比我還像新娘躏嚎。我一直安慰自己,他們只是感情好菩貌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布卢佣。 她就那樣靜靜地躺著,像睡著了一般箭阶。 火紅的嫁衣襯著肌膚如雪虚茶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天仇参,我揣著相機(jī)與錄音嘹叫,去河邊找鬼。 笑死诈乒,一個(gè)胖子當(dāng)著我的面吹牛罩扇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播怕磨,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼喂饥,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了肠鲫?” 一聲冷哼從身側(cè)響起员帮,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎滩届,沒想到半個(gè)月后集侯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體被啼,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年棠枉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浓体。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡辈讶,死狀恐怖命浴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情贱除,我是刑警寧澤生闲,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站月幌,受9級(jí)特大地震影響碍讯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜扯躺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一捉兴、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧录语,春花似錦倍啥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蒲稳,卻和暖如春氮趋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背弟塞。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工凭峡, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人决记。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓摧冀,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親系宫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子索昂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 函數(shù)和對(duì)象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對(duì)于任何一門語(yǔ)言來(lái)說(shuō)都是核心的概念扩借。通過(guò)函數(shù)可以封裝任意多條語(yǔ)句椒惨,而且...
    道無(wú)虛閱讀 4,566評(píng)論 0 5
  • 函數(shù)參數(shù)的默認(rèn)值 基本用法 在ES6之前,不能直接為函數(shù)的參數(shù)指定默認(rèn)值潮罪,只能采用變通的方法康谆。 上面代碼檢查函數(shù)l...
    呼呼哥閱讀 3,392評(píng)論 0 1
  • 函數(shù)參數(shù)的默認(rèn)值 基本用法 在ES6之前领斥,不能直接為函數(shù)的參數(shù)指定默認(rèn)值,只能采用變通的方法沃暗。 上面代碼檢查函數(shù)l...
    陳老板_閱讀 449評(píng)論 0 1
  • 早安月洛。今天一覺醒來(lái)天已大亮,外面天湛藍(lán) 孽锥,太陽(yáng)初升嚼黔,開始了一天的生活…… 今天說(shuō)說(shuō)回憶,提到這兩個(gè)字惜辑,畫面感十足 ...
    江云的心靈書寫閱讀 230評(píng)論 0 0
  • 許久未見,你好嗎撵彻? 從上次我們見面一晃9年的時(shí)間過(guò)去了钓株。 9年前的那天,我們坐在一起陌僵,你暖暖的微笑,年輕的臉龐洋溢...
    vanbillina閱讀 235評(píng)論 0 0