JavaScript中的this指向總結(jié)

前置知識:作用域與this

要想徹底明白 \color{#ff0000}{this}的行為,就要明白作用域和 \color{#ff0000}{this}的關(guān)系走芋。
\color{#ff0000}{JavaScript}中采用的詞法作用域全闷,即在函數(shù)聲明時(shí)叉寂,就已經(jīng)確定了其作用域,而與函數(shù)在任何處調(diào)用沒有關(guān)系总珠;而 \color{#ff0000}{this}是在運(yùn)行時(shí)確定的屏鳍,因此對于同一個(gè)函數(shù)而言,不同的調(diào)用方式會導(dǎo)致不同的 \color{#ff0000}{this}綁定(暫時(shí)不考慮箭頭函數(shù)局服,下文會單獨(dú)講)孕蝉。這一點(diǎn)對于this很重要。

四種綁定方式

在各種書籍和博客上都會提到 \color{#ff0000}{this}的綁定方式有四種腌逢,分別如下(長不了考慮箭頭函數(shù))

  • 默認(rèn)綁定
  • 隱式綁定
  • 顯示綁定
  • \color{#ff0000}{new}綁定

1降淮、默認(rèn)綁定

默認(rèn)綁定是指,當(dāng)函數(shù)獨(dú)立調(diào)用時(shí)(即使沒有調(diào)用者)搏讶,\color{#ff0000}{this} 指向\color{#ff0000}{window}

// 代碼1.1
function foo(){
  console.log(this)
}
foo() // window

而在嚴(yán)格模式下 \color{#ff0000}{this}\color{#ff0000}{undefined}

// 代碼1.2
'use strict'
function foo(){
  console.log(this)
}
foo() // undefined

這種\color{#ff0000}{this}綁定形式很好理解佳鳖,此外,值得注意的是媒惕,立即執(zhí)行函數(shù)表達(dá)式 也是函數(shù)獨(dú)立調(diào)用的一種系吩,其中\color{#ff0000}{this}也會指向window

// 代碼1.3
(function(){
  console.log(this) //window
})()

下面這種形式也是函數(shù)獨(dú)立調(diào)用,\color{#ff0000}{this}指向\color{#ff0000}{window}

代碼1.4
function bar(){
  console.log(this)
}
let obj = {
  foo:function(){
    bar();
  }
}
obj.foo() // window
2妒蔚、隱式綁定

隱式綁定與默認(rèn)綁定相對應(yīng)穿挨,隱式綁定 可以大致理解為誰調(diào)用,\color{#ff0000}{this}就指向誰肴盏,即\color{#ff0000}{this}指向當(dāng)前執(zhí)行上下文科盛。

// 代碼2.1
let obj  ={
  foo:function(){
    console.log(this)
  }
}
obj.foo() // obj

上面的代碼中,先在全局聲明了\color{#ff0000}{foo}函數(shù)菜皂,之后將其賦值給\color{#ff0000}{obj}的foo方法贞绵。再次強(qiáng)調(diào),\color{#ff0000}{this}是執(zhí)行的時(shí)候確定恍飘,與作用域無關(guān)榨崩。因此谴垫,雖然函數(shù)\color{#ff0000}{foo}是在全局聲明的,但是調(diào)用者是obj母蛛,也就是執(zhí)行時(shí)上下文\color{#ff0000}{tobj}對象翩剪,因此\color{#ff0000}{this}指向\color{#ff0000}{obj}對象。

是不是感覺自己懂了彩郊?別急前弯,再看看下邊的代碼

// 代碼2.3
let obj ={
  foo:function(){
    console.log(this) // window
  }
};
let bar = obj.foo
bar();

obj.foo() 

解析如下:

  • 首先不要一看到函數(shù),就開始在腦海中運(yùn)行焦辅,只要把它看作是一個(gè)變量就好博杖,不要考慮函數(shù)體里面的代碼,等到執(zhí)行時(shí)再去進(jìn)行解析筷登。
  • obj.off方法聲明部分剃根,只需要理解為在堆內(nèi)存中開辟了一塊空間,并由obj.foo持有這塊內(nèi)存空間的作用前方,由于函數(shù)尚未執(zhí)行狈醉,因此還沒有確定\color{#ff0000}{this}
  • \color{#ff0000}{obj.foo}賦值給\color{#ff0000}{bar},也就是將函數(shù)的引用拷貝一份給bar
  • \color{#ff0000}{bar}獨(dú)立調(diào)用惠险,因此this指向window

這也就是很多文章中提到的隱式丟失苗傅。
代碼2.3中的this隱式丟失是由于變量賦值導(dǎo)致的,此外班巩,間接引用也會造成隱式丟失渣慕。

// 代碼2.4
function logThis(){
  console.log(this)
}
let obj1 = { log: logThis }
let obj2 ={ }

obj1.log(); //obj1
(obj2.log = obj1.log)() // window

這是由于賦值表達(dá)式(obj2.log = obj1.log)的返回值是函數(shù)logThis的引用,上面的代碼可以理解為

let retFn = (obj2.log = obj1.log)
retFn();

可以看出抱慌,這相當(dāng)于函數(shù)獨(dú)立調(diào)用 符合默認(rèn)綁定的規(guī)則逊桦。
還有一種比較隱蔽的導(dǎo)致隱式丟失的情況:

//代碼2.5
let obj ={
  foo:function(){
    console.log(this)
  }
}
function bar(cb){
  cb();
}
bar(obj.foo)  // window

答案同樣是window,這就是由于參數(shù)傳遞導(dǎo)致的this隱式丟失抑进,分析如下强经。

  • 聲明\color{#ff0000}{obj.foo},在堆內(nèi)存中開辟一塊空間寺渗,并由\color{#ff0000}{obj.foo}持有對內(nèi)存的引用匿情。
  • \color{#ff0000}{obj.foo}作為函數(shù)\color{#ff0000}{bar}的參數(shù),\color{#ff0000}{bar}獨(dú)立調(diào)用信殊,函數(shù)執(zhí)行過程如下所示炬称;
    1、在函數(shù)作用域內(nèi)聲明cb,并將實(shí)參\color{#ff0000}{obj.foo}賦值給形參cb
    2鸡号、cb獨(dú)立調(diào)用转砖。
    從以上的分析可以看出,參數(shù)傳遞導(dǎo)致的隱式丟失與變量賦值導(dǎo)致的隱式丟失鲸伴,從本質(zhì)上來說是一樣的府蔗。

參數(shù)傳遞導(dǎo)致的this隱式丟失在JavaScript內(nèi)置API中也十分常見,比如:Array.prototype.map汞窗,setTimeout姓赤,ES6的Promise構(gòu)造函數(shù),node中的readFile等等仲吏。這些函數(shù)接受一個(gè)回調(diào)函數(shù)作為參數(shù)不铆,并在某一時(shí)刻執(zhí)行它,執(zhí)行模式與下面的偽代碼類似

// 代碼2.5
function fn(cb) {
  // {...代碼...}
  cb()
  // {...代碼...}
}

參數(shù)傳遞導(dǎo)致的隱式丟失比較隱蔽裹唆,不容易發(fā)現(xiàn)誓斥,需要額外留意。

this隱式綁定是指誰調(diào)用许帐,this就指向誰
經(jīng)常與隱式綁定一同出現(xiàn)的是隱式丟失劳坑,隱式丟失常見于三種情況,變量賦值成畦,簡介引用和參數(shù)傳遞(常見于回調(diào)函數(shù))

3距芬、顯示綁定

最常見的顯示綁定就是\color{#ff0000}{Function.prototype}上的三個(gè)方法:\color{#ff0000}{call}\color{#ff0000}{apply}循帐、\color{#ff0000}{bind}框仔。
相信這幾個(gè)方法日常用的就比較多了吧,也就不做過多的贅述拄养。但是有一點(diǎn)還是要注意离斩,就是通過以上三個(gè)方法綁定后的this之后,就無法通過這三個(gè)方法繼續(xù)改變this指向了瘪匿,也就是說跛梗,只有一次綁定有效,后續(xù)綁定就會失敗柿顶。

\color{#ff0000}{bind}有一個(gè)點(diǎn)需要注意茄袖,就是返回的bound沒有prototype屬性,但是可以用let ins = new bound()來創(chuàng)建來創(chuàng)建對象嘁锯。并且ins instanceof boundtrue宪祥,這一點(diǎn)規(guī)范中有提到,如果instanceof的對象是一個(gè)bind之后的函數(shù)家乘,就會找原來的函數(shù)進(jìn)行操作蝗羊。

image.png

除了上面提到的三個(gè)顯式綁定的方法,還有另外兩種綁定方式仁锯,我也不知道該怎么分類耀找,姑且放到顯式綁定里吧:事件的綁定和部分API提供的綁定方式。

第一種是事件處理函數(shù),在事件處理函數(shù)中野芒,this指向綁定事件的元素蓄愁。第二種是例如Array.prototype.map支持第二個(gè)參數(shù)來指定回調(diào)函數(shù)中的this指向。值得一提的是狞悲,通過bind可以改變這兩種情況中函數(shù)的this指向撮抓。

4、new綁定

當(dāng)使用new 來實(shí)例化一個(gè)構(gòu)造函數(shù)時(shí)摇锋,this指向?qū)嵗?/p>

優(yōu)先級

綁定的優(yōu)先級就比較簡單了丹拯,這四種方式從上到下權(quán)重依次增加:new > 顯式綁定 > 隱式綁定 > 默認(rèn)綁定

箭頭函數(shù)

前面說了這么多,都是針對普通函數(shù)荸恕,也就是用function關(guān)鍵字聲明的函數(shù)乖酬。ES6中引入了箭頭函數(shù),都說箭頭函數(shù)沒有this融求,但是又能在箭頭函數(shù)中使用this咬像,這可能會給很多人造成困惑。其實(shí)双肤,弄清楚箭頭函數(shù)的this很簡單施掏,只需要把箭頭函數(shù)的this看做一個(gè)普通的變量,由于箭頭函數(shù)自身沒有this茅糜,所以需要沿著作用域鏈向上進(jìn)行查找七芭,直到找到this(普通函數(shù)或者window)。也就是說蔑赘,箭頭函數(shù)的this由兩方面決定:詞法作用域和父級函數(shù)的this狸驳。因此,理解了普通函數(shù)的this指向缩赛,箭頭函數(shù)的this也就很簡單了耙箍。

那么箭頭函數(shù)和call一起使用會發(fā)生什么呢?由于箭頭函數(shù)自身是沒有this的酥馍,而call是改變目標(biāo)函數(shù)的this指向辩昆,因此對箭頭函數(shù)使用call是無效的,箭頭函數(shù)依然會根據(jù)詞法作用域來查找this旨袒。

轉(zhuǎn)自:https://juejin.cn/post/6935652420265771044

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末汁针,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子砚尽,更是在濱河造成了極大的恐慌施无,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件必孤,死亡現(xiàn)場離奇詭異猾骡,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門兴想,熙熙樓的掌柜王于貴愁眉苦臉地迎上來幢哨,“玉大人,你說我怎么就攤上這事襟企≈雒矗” “怎么了狮含?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵顽悼,是天一觀的道長。 經(jīng)常有香客問我几迄,道長蔚龙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任映胁,我火速辦了婚禮木羹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘解孙。我一直安慰自己坑填,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布弛姜。 她就那樣靜靜地躺著脐瑰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪廷臼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機(jī)與錄音迄汛,去河邊找鬼扣墩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛莱没,可吹牛的內(nèi)容都是我干的初肉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼饰躲,長吁一口氣:“原來是場噩夢啊……” “哼牙咏!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起属铁,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤眠寿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后焦蘑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體盯拱,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了狡逢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片宁舰。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖奢浑,靈堂內(nèi)的尸體忽然破棺而出蛮艰,到底是詐尸還是另有隱情,我是刑警寧澤雀彼,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布壤蚜,位于F島的核電站,受9級特大地震影響徊哑,放射性物質(zhì)發(fā)生泄漏袜刷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一莺丑、第九天 我趴在偏房一處隱蔽的房頂上張望著蟹。 院中可真熱鬧,春花似錦梢莽、人聲如沸萧豆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽涮雷。三九已至,卻和暖如春葡粒,著一層夾襖步出監(jiān)牢的瞬間份殿,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工嗽交, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卿嘲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓夫壁,卻偏偏與公主長得像拾枣,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子盒让,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

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