javascript
JS高级——深入剖析函数中的this指向问题
一、this到底指向什么呢?
我們先說(shuō)一個(gè)最簡(jiǎn)單的,this在全局作用域下指向什么?
- 這個(gè)問(wèn)題非常容易回答,在瀏覽器中測(cè)試就是指向window
但是,開(kāi)發(fā)中很少直接在全局作用于下去使用this,通常都是在函數(shù)中使用。
- 所有的函數(shù)在被調(diào)用時(shí),都會(huì)創(chuàng)建一個(gè)執(zhí)行上下文:
- 這個(gè)上下文中記錄著函數(shù)的調(diào)用棧、AO對(duì)象等;
- this也是其中的一條記錄;
定義一個(gè)函數(shù),我們采用三種不同的方式對(duì)它進(jìn)行調(diào)用,它產(chǎn)生了三種不同的結(jié)果:
這個(gè)的案例可以給我們什么樣的啟示呢?
this到底是怎么樣的綁定規(guī)則呢?
- 綁定一:默認(rèn)綁定;
- 綁定二:隱式綁定;
- 綁定三:顯示綁定;
- 綁定四:new綁定;
二、規(guī)則一:默認(rèn)綁定
什么情況下使用默認(rèn)綁定呢?獨(dú)立函數(shù)調(diào)用。
- 獨(dú)立的函數(shù)調(diào)用我們可以理解成函數(shù)沒(méi)有被綁定到某個(gè)對(duì)象上進(jìn)行調(diào)用;
三、規(guī)則二:隱式綁定
另外一種比較常見(jiàn)的調(diào)用方式是通過(guò)某個(gè)對(duì)象進(jìn)行調(diào)用的:
- 也就是它的調(diào)用位置中,是通過(guò)某個(gè)對(duì)象發(fā)起的函數(shù)調(diào)用。
四、規(guī)則三:顯示綁定
隱式綁定有一個(gè)前提條件:
- 必須在調(diào)用的對(duì)象內(nèi)部有一個(gè)對(duì)函數(shù)的引用(比如一個(gè)屬性);
- 如果沒(méi)有這樣的引用,在進(jìn)行調(diào)用時(shí),會(huì)報(bào)找不到該函數(shù)的錯(cuò)誤;
- 正是通過(guò)這個(gè)引用,間接的將this綁定到了這個(gè)對(duì)象上;
如果我們不希望在 對(duì)象內(nèi)部 包含這個(gè)函數(shù)的引用,同時(shí)又希望在這個(gè)對(duì)象上進(jìn)行強(qiáng)制調(diào)用,該怎么做呢?
- JavaScript所有的函數(shù)都可以使用call和apply方法(這個(gè)和Prototype有關(guān))。
call和apply方法的區(qū)別其實(shí)非常簡(jiǎn)單,第一個(gè)參數(shù)是相同的,后面的參數(shù):apply為數(shù)組,call為參數(shù)列表; - 這兩個(gè)函數(shù)的第一個(gè)參數(shù)都要求是一個(gè)對(duì)象,這個(gè)對(duì)象的作用是什么呢?就是給this準(zhǔn)備的。
- 在調(diào)用這個(gè)函數(shù)時(shí),會(huì)將this綁定到這個(gè)傳入的對(duì)象上。
- 因?yàn)樯厦娴倪^(guò)程,我們明確的綁定了this指向的對(duì)象,所以稱(chēng)之為 顯示綁定。
通過(guò)call或者apply綁定this對(duì)象:
如果我們希望一個(gè)函數(shù)總是顯示的綁定到一個(gè)對(duì)象上,可以怎么做呢?
五、內(nèi)置函數(shù)的綁定思考
有些時(shí)候,我們會(huì)調(diào)用一些JavaScript的內(nèi)置函數(shù),或者一些第三方庫(kù)中的內(nèi)置函數(shù)。
- 這些內(nèi)置函數(shù)會(huì)要求我們傳入另外一個(gè)函數(shù);
- 我們自己并不會(huì)顯示的調(diào)用這些函數(shù),而且JavaScript內(nèi)部或者第三方庫(kù)內(nèi)部會(huì)幫助我們執(zhí)行;
- 這些函數(shù)中的this又是如何綁定的呢?
setTimeout、數(shù)組的forEach、div的點(diǎn)擊:
注意:forEach()第二個(gè)參數(shù)可以綁定this
六、規(guī)則四:new綁定
七、規(guī)則優(yōu)先級(jí)
學(xué)習(xí)了四條規(guī)則,接下來(lái)開(kāi)發(fā)中我們只需要去查找函數(shù)的調(diào)用應(yīng)用了哪條規(guī)則即可,但是如果一個(gè)函數(shù)調(diào)用位置應(yīng)用了多條規(guī)則,優(yōu)先級(jí)誰(shuí)更高呢?
1.默認(rèn)規(guī)則的優(yōu)先級(jí)最低
- 毫無(wú)疑問(wèn),默認(rèn)規(guī)則的優(yōu)先級(jí)是最低的,因?yàn)榇嬖谄渌?guī)則時(shí),就會(huì)通過(guò)其他規(guī)則的方式來(lái)綁定this
2.顯示綁定優(yōu)先級(jí)高于隱式綁定
3.new綁定優(yōu)先級(jí)高于隱式綁定
4.new綁定優(yōu)先級(jí)高于bind
- new綁定和call、apply是不允許同時(shí)使用的,所以不存在誰(shuí)的優(yōu)先級(jí)更高
- new綁定可以和bind一起使用,new綁定優(yōu)先級(jí)更高
八、this規(guī)則之外 – 忽略顯示綁定
我們講到的規(guī)則已經(jīng)足以應(yīng)付平時(shí)的開(kāi)發(fā),但是總有一些語(yǔ)法,超出了我們的規(guī)則之外。(神話(huà)故事和動(dòng)漫中總是有類(lèi)似這樣的人物)
如果在顯示綁定中,我們傳入一個(gè)null或者undefined,那么這個(gè)顯示綁定會(huì)被忽略,使用默認(rèn)規(guī)則:
九、this規(guī)則之外 - 間接函數(shù)引用
另外一種情況,創(chuàng)建一個(gè)函數(shù)的 間接引用,這種情況使用默認(rèn)綁定規(guī)則。
- 賦值表達(dá)式(obj2.foo = obj1.foo)的結(jié)果是foo函數(shù);
- foo函數(shù)被直接調(diào)用,那么是默認(rèn)綁定;
十、箭頭函數(shù) arrow function
箭頭函數(shù)是ES6之后增加的一種編寫(xiě)函數(shù)的方法,并且它比函數(shù)表達(dá)式要更加簡(jiǎn)潔:
- 箭頭函數(shù)不會(huì)綁定this、arguments屬性;
- 箭頭函數(shù)不能作為構(gòu)造函數(shù)來(lái)使用(不能和new一起來(lái)使用,會(huì)拋出錯(cuò)誤);
箭頭函數(shù)如何編寫(xiě)呢?
- (): 函數(shù)的參數(shù)
- {}: 函數(shù)的執(zhí)行體
十一、箭頭函數(shù)的編寫(xiě)優(yōu)化
十二、this規(guī)則之外 – ES6箭頭函數(shù)
箭頭函數(shù)不使用this的四種標(biāo)準(zhǔn)規(guī)則(也就是不綁定this),而是根據(jù)外層作用域來(lái)決定this。
我們來(lái)看一個(gè)模擬網(wǎng)絡(luò)請(qǐng)求的案例:
-
這里我使用setTimeout來(lái)模擬網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求到數(shù)據(jù)后如何可以存放到data中呢?
-
我們需要拿到obj對(duì)象,設(shè)置data;
-
但是直接拿到的this是window,
-
我們需要在外層定義:var _this = this
-
在setTimeout的回調(diào)函數(shù)中使用_this就代表了obj對(duì)象
之前的代碼在ES6之前是我們最常用的方式,從ES6開(kāi)始,我們會(huì)使用箭頭函數(shù): -
為什么在setTimeout的回調(diào)函數(shù)中可以直接使用this呢?
-
因?yàn)榧^函數(shù)并不綁定this對(duì)象,那么this引用就會(huì)從上層作用于中找到對(duì)應(yīng)的this
十三、面試題
總結(jié)
以上是生活随笔為你收集整理的JS高级——深入剖析函数中的this指向问题的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Node使用MySQL
- 下一篇: python dataframe 列_p