摘要:在這里,如果用箭頭函數(shù),可以這樣改寫箭頭函數(shù)并沒有自己的,所以事件處理函數(shù)的調(diào)用者并不受影響。比如,在需要?jiǎng)討B(tài)上下文的場(chǎng)景中,使用箭頭函數(shù)需要格外地小心,這些場(chǎng)景包括對(duì)象的方法原型方法事件的回調(diào)構(gòu)造函數(shù)。
前言
年味兒漸散,收拾下心情,繼續(xù)敲代碼吧。
對(duì)于即將到來(lái)金三銀四的求職季,相信不少同學(xué)都在默默地做著準(zhǔn)備。本系列旨在梳理前端龐雜的知識(shí)點(diǎn),并盡可能通俗易懂地表述出來(lái),也希望能幫到有需要的同學(xué)。
這是前端面試題系列的第 5 篇,你可能錯(cuò)過了前面的篇章,可以在這里找到:
this 的原理以及用法
偽類與偽元素的區(qū)別及實(shí)戰(zhàn)
如何實(shí)現(xiàn)一個(gè)圣杯布局?
今日頭條 面試題和思路解析
面試中,我經(jīng)常會(huì)問及 ES6 的知識(shí)點(diǎn),因?yàn)槠綍r(shí)工作中用得很多。當(dāng)問到箭頭函數(shù)時(shí),不少候選人都會(huì)贊嘆地說(shuō):箭頭函數(shù)很好用,而且再也不用操心 this 的指向了。
我接著問:箭頭函數(shù)是挺好用的,但是你有沒有遇到過,不適合使用箭頭函數(shù)的場(chǎng)景呢?
這時(shí),能回答得上來(lái)的候選人就很少了。箭頭函數(shù)在大多數(shù)情況下,是很好用的,但是為什么在有些場(chǎng)景,使用箭頭函數(shù)后會(huì)產(chǎn)生問題?是不是箭頭函數(shù)還不夠完善?又有哪些場(chǎng)景會(huì)發(fā)生問題?該如何解決呢?這,正是本文想要一起探討的。
箭頭函數(shù)的寫法為什么叫箭頭函數(shù)( Arrow Function )?因?yàn)樗膶懛ǎ瓷先ゾ褪且粋€(gè)箭頭:
const multiply = num => num * num;
它等價(jià)于:
const multiply = function (num) { return num * num; };
此外,還可以傳多個(gè)參數(shù),以及可變參數(shù)。
// 多參數(shù) const multiply = (num1, num2) => num1 * num2; // 可變參數(shù) const sum = (num1, num2, ...rest) => { let result = num1 + num2; for (let i = 0; i < rest.length; i++) { result += rest[i]; } return result; };
當(dāng)有多條語(yǔ)句時(shí),需要配上 {...} 和 return。
另外,如果返回的結(jié)果是對(duì)象,則需要配上 (),像下面這樣:
const func = val => ({ value: val });
從上述的寫法來(lái)看,相較普通函數(shù)而言,箭頭函數(shù)的確簡(jiǎn)便了很多,提升了我們代碼的易用性。但它并非在任何場(chǎng)景下都適用,接下來(lái),將會(huì)介紹幾種不適合箭頭函數(shù)的場(chǎng)景,并會(huì)提出可行的解決方案。
不適合的場(chǎng)景 1、對(duì)象的方法看下面這個(gè)例子:
const obj = { x: 1, print: () => { console.log(this === window); // => true console.log(this.x); // undefined } }; obj.print();
this.x 打印出來(lái)是 undefined。為什么?然后,我在上面加了一行,發(fā)現(xiàn) this 指向了 window。
解析:print 方法用了箭頭函數(shù),其內(nèi)部的 this 指向的還是上下文 window,上下文中并沒有定義 x,所以 this.x 輸出為 undefined。
解決辦法:用 ES6 的短語(yǔ)法,或者傳統(tǒng)的函數(shù)表達(dá)式都可以。所以,print 要這樣寫:
print () { console.log(this === test); // => true console.log(this.x); // 1 }2、原型方法
同樣的規(guī)則也適用于原型方法的定義,使用箭頭函數(shù)會(huì)導(dǎo)致運(yùn)行時(shí)的執(zhí)行上下文錯(cuò)誤。
function Cat (name) { this.name = name; } Cat.prototype.sayCatName = () => { console.log(this === window); // => true return this.name; }; const cat = new Cat("Miao"); cat.sayCatName(); // => undefined
解決辦法是:用回傳統(tǒng)的函數(shù)表達(dá)式,像下面這樣:
Cat.prototype.sayCatName = function () { console.log(this === cat); // => true return this.name; };
sayCatName 變回傳統(tǒng)的函數(shù)表達(dá)式之后,被調(diào)用時(shí)的執(zhí)行上下文就會(huì)指向新創(chuàng)建的 cat 實(shí)例。
3、事件的回調(diào)看下面這個(gè)例子:
const btn = document.getElementById("myButton"); btn.addEventListener("click", () => { console.log(this === window); // => true this.innerHTML = "Clicked button"; });
這里會(huì)有問題,因?yàn)?this 指向了 window。
解析:當(dāng)為一個(gè) DOM 事件綁定回調(diào)函數(shù)后,觸發(fā)回調(diào)函數(shù)時(shí)的 this,需要指向當(dāng)前發(fā)生事件的 DOM 節(jié)點(diǎn),也就是這里的 btn。當(dāng)回調(diào)發(fā)生時(shí),瀏覽器會(huì)用 btn 的上下文去調(diào)用處理函數(shù)。所以最后的 this.innerHTML 等價(jià)于 window.innerHTML,問題就在這里。
解決辦法:用函數(shù)表達(dá)式代替箭頭函數(shù)。像這樣:
btn.addEventListener("click", function() { console.log(this === btn); // => true this.innerHTML = "Clicked button"; });
另外,在 react 中的事件回調(diào),也經(jīng)常會(huì)遇到類似的問題。
// jsx render // callback handleClickButton () { ... }
注意:這里 onClick 的回調(diào)函數(shù),并非字符串,而是一個(gè)實(shí)實(shí)在在的函數(shù)。可以將 onClick 理解為一個(gè)中間變量,所以 react 在處理函數(shù)時(shí)的 this 指向就會(huì)丟失。
為了解決這個(gè)問題,我們需要為回調(diào)函數(shù)綁定 this,使得事件處理函數(shù)無(wú)論如何傳遞,this 都指向我們實(shí)例化的那個(gè)對(duì)象。
在這里,如果用箭頭函數(shù),可以這樣改寫:
箭頭函數(shù)并沒有自己的 this,所以事件處理函數(shù)的調(diào)用者并不受影響。
4、構(gòu)造函數(shù)箭頭函數(shù)不能通過 new 關(guān)鍵字調(diào)用。
const Message = (text) => { this.text = text; }; var helloMessage = new Message("Hello World!"); // Uncaught TypeError: Message is not a constructor
解析:從報(bào)錯(cuò)信息可以看出,箭頭函數(shù)沒有 constructor 方法,所以不能用作構(gòu)造函數(shù)。 JavaScript 會(huì)通過拋出異常的方式,進(jìn)行隱式地預(yù)防。
解決方法:用函數(shù)表達(dá)式代替箭頭函數(shù)。
總結(jié)回顧 MDN 給出的解釋:箭頭函數(shù)表達(dá)式的語(yǔ)法比函數(shù)表達(dá)式更短,并且沒有自己的this,arguments,super或 new.target。這些函數(shù)表達(dá)式更適用于那些本來(lái)需要匿名函數(shù)的地方,并且它們不能用作構(gòu)造函數(shù)。
所以說(shuō),箭頭函數(shù)無(wú)疑是 ES6 帶來(lái)的重大改進(jìn),在正確的場(chǎng)合使用箭頭函數(shù),能讓代碼變得更加簡(jiǎn)潔短小。但箭頭函數(shù)也不是萬(wàn)能的,不能用的時(shí)候,千萬(wàn)別硬往上套。比如,在需要?jiǎng)討B(tài)上下文的場(chǎng)景中,使用箭頭函數(shù)需要格外地小心,這些場(chǎng)景包括:對(duì)象的方法、原型方法、事件的回調(diào)、構(gòu)造函數(shù)。并非一定要用箭頭函數(shù),才能解決問題。
PS:歡迎關(guān)注我的公眾號(hào) “超哥前端小?!保涣鞲嗟南敕ㄅc技術(shù)。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/101575.html
摘要:但是有一個(gè)總的原則那就是總會(huì)指向,調(diào)用函數(shù)的那個(gè)對(duì)象。作為對(duì)象方法的調(diào)用函數(shù)作為某個(gè)對(duì)象的方法調(diào)用,這時(shí)就指這個(gè)上級(jí)對(duì)象。 showImg(https://segmentfault.com/img/bVbnvF7?w=750&h=422); 這是前端面試題系列的第 4 篇,你可能錯(cuò)過了前面的篇章,可以在這里找到: 偽類與偽元素的區(qū)別及實(shí)戰(zhàn) 如何實(shí)現(xiàn)一個(gè)圣杯布局? 今日頭條 面試題和思...
摘要:原題如下寫一個(gè)方法,當(dāng)使用下面的語(yǔ)法調(diào)用時(shí),能正常工作這道題要考察的,就是對(duì)函數(shù)柯里化的理解。當(dāng)參數(shù)只有一個(gè)的時(shí)候,進(jìn)行柯里化的處理。這其實(shí)就是函數(shù)柯里化的簡(jiǎn)單應(yīng)用。 showImg(https://segmentfault.com/img/bVbopGm?w=620&h=350); 前言 這是前端面試題系列的第 6 篇,你可能錯(cuò)過了前面的篇章,可以在這里找到: ES6 中箭頭函數(shù)的...
摘要:并總結(jié)經(jīng)典面試題集各種算法和插件前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快速搭建項(xiàng)目。 本文是關(guān)注微信小程序的開發(fā)和面試問題,由基礎(chǔ)到困難循序漸進(jìn),適合面試和開發(fā)小程序。并總結(jié)vue React html css js 經(jīng)典面試題 集各種算法和插件、前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快...
摘要:并總結(jié)經(jīng)典面試題集各種算法和插件前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快速搭建項(xiàng)目。 本文是關(guān)注微信小程序的開發(fā)和面試問題,由基礎(chǔ)到困難循序漸進(jìn),適合面試和開發(fā)小程序。并總結(jié)vue React html css js 經(jīng)典面試題 集各種算法和插件、前端視頻源碼資源于一身的文檔,優(yōu)化項(xiàng)目,在瀏覽器端的層面上提升速度,幫助初中級(jí)前端工程師快...
閱讀 3491·2023-04-25 22:45
閱讀 1294·2021-11-11 16:54
閱讀 2802·2019-08-30 15:44
閱讀 3198·2019-08-30 15:44
閱讀 1654·2019-08-30 13:55
閱讀 948·2019-08-29 18:45
閱讀 1207·2019-08-29 17:25
閱讀 1017·2019-08-29 12:59