this的四種綁定之詳細介紹


this是一個關鍵字雏吭,不是變量牵触,也不是屬性名淮悼,JavaScript的語法不允許給this賦值。和變量不同揽思,關鍵字this沒有作用域的限制袜腥,嵌套的函數(shù)不會從調用它的函數(shù)中繼承this。如果嵌套函數(shù)作為方法調用钉汗,其this的值指向調用它的對象羹令。如果嵌套函數(shù)作為函數(shù)調用,其this值不是全局對象就是undefined(非嚴格模式下是全局對象(即window對象)损痰,嚴格模式下是undefined)福侈。很多人誤以為調用嵌套函數(shù)時,this會指向調用外層函數(shù)的上下文卢未。如果你想訪問這個外部函數(shù)的this值肪凛,需要將this的值保存在一個變量中,這個變量和內部函數(shù)都同在一個作用域內辽社。通常使用變量self來保存this伟墙。

記住一點:函數(shù)中的this總指向調用它的對象。(金句)

對應函數(shù)的四種調用方法(函數(shù)調用滴铅、方法調用戳葵、通過call()和apply()方法的間接調用和構造函數(shù)調用),this有四種綁定方式失息,即:默認綁定譬淳、隱式綁定、顯式綁定和new綁定盹兢。


默認綁定

當一個函數(shù)沒有明確的調用對象的時候,也就是單純作為獨立函數(shù)調用的時候守伸,將對函數(shù)的this使用默認綁定:綁定到全局的window對象绎秒。

注:以函數(shù)形式調用的函數(shù)通常不使用this關鍵字,不過尼摹,此時的“this”可以用來判斷當前是否是嚴格模式见芹。

代碼說明:

本代碼第16行是IIFE(立即執(zhí)行函數(shù))的寫法。

嚴格模式下蠢涝,this指向undefined玄呛,所以第13行代碼打印出false,14行打印出true

非嚴格模式下(即注釋掉第9行代碼)和二,this指向window徘铝,所以第13行代碼打印出true,14行打印出false。

注:除非特別說明惕它,本文的代碼默認運行在非嚴格模式下怕午。

一、簡單的函數(shù)調用寫法


代碼說明:

第19-24行代碼很容易就能看懂淹魄,第24行就是普通的函數(shù)調用郁惜,a()作為獨立函數(shù)調用,此時甲锡,this指向window或者undefined兆蕉。

二、嵌套函數(shù)調用

此時的代碼你看懂了嗎缤沦?b()是什么方式調用虎韵?obj.foo()是什么方式的調用?

代碼說明:

第36行疚俱,b()依然是獨立調用劝术,它只是嵌套在foo函數(shù)中。所以它的指向依然是是默認指向(window or undefined)呆奕,而全局變量a的值是0(從第27行代碼可看出來)养晋,所以此時34行代碼打印出 0.

Q:如果將34行代碼復制到36行代碼的下面一行呢?會出現(xiàn)什么效果梁钾?

運行代碼會發(fā)現(xiàn)第37行代碼打印出1绳泉,這是為什么呢?

這就是馬上要講的函數(shù)的另一種調用方式-----方法調用姆泻,方法調用引發(fā)this的隱式綁定零酪。


隱式綁定

首先解釋下函數(shù)的方法調用

一個方法無非是個保存在一個對象的屬性里的JavaScript函數(shù)。白話說拇勃,就是在一個對象中定義函數(shù)四苇,調用該函數(shù)就是方法調用,還記得前文提到的金句嗎方咆?“函數(shù)中的this總指向調用它的對象”月腋,此時的this就指向調用該函數(shù)的對象。

還是用上面的代碼(第27行---40行)

代碼說明:

先說一下第一個this:

第27行定義了一個變量a瓣赂,很顯然榆骚,此時的a是全局變量。第28行定義了一個obj對象煌集,在obj對象中妓肢,第29行定義了一個變量a,此時苫纤,a是obj對象中的局部變量碉钠,第30行定義一個foo函數(shù)纲缓,這里的foo函數(shù)作用域也是obj對象,第32行是在foo函數(shù)里定義了一個b函數(shù)放钦,這里的b函數(shù)的作用域是foo函數(shù)色徘,第36行是在foo函數(shù)中,調用b函數(shù)操禀,注意哦褂策,此時的調用是獨立調用哦,就是普通的函數(shù)調用哦颓屑,所以當40行調用foo函數(shù)時斤寂,b函數(shù)被調用,b函數(shù)里的this指向全局揪惦,所以遍搞,打印出 0 。

現(xiàn)在介紹第二個this:

當代碼流執(zhí)行到第40行時器腋,調用obj對象中的foo函數(shù)溪猿,正如前文所講,此時的調用就稱作函數(shù)的方法調用纫塌。函數(shù)的使用方法調用時诊县,this指向調用該方法的對象,在這里就是this指向obj對象措左。而obj對象中依痊,a的值在第29行被賦值為1,所以第37行代碼打印出 1 怎披。

隱式丟失

前文之所以稱作隱式綁定胸嘁,是因為此時的this隱式綁定在obj對象上。所以this的指向是obj對象凉逛。然而性宏,當綁定至上下文對象的函數(shù)被賦值給一個新的函數(shù),或者傳遞給回調函數(shù)時状飞,函數(shù)中的 this容易丟失掉綁定對象衔沼,此時this執(zhí)行默認綁定規(guī)則

一昔瞧、賦值丟失(綁定至上下文對象的函數(shù)被賦值給一個新的函數(shù))

代碼說明:

第56行定義全局變量a,并賦值為1菩佑,57行定義obj對象自晰,58行在obj對象中定義局部變量a,并賦值為2稍坯,59行在obj對象中定義foo函數(shù)酬荞。63行很奇怪是吧搓劫,為了方便介紹,我們將其等價成a=b,

深度解釋“a=b”賦值語句:

第一步混巧,計算表達式a枪向,得到a的地址refa;

第二步,計算表達式b, 得到b的值valueb;

第三步:將valueb賦給refa

第四步:返回valueb

也就是說咧党,obj.foo = obj.foo會返回第二個obj.foo所指向的函數(shù)表達式秘蛔,所以第63行代碼就等價于

很顯然,64行代碼時定義了一個新的函數(shù)傍衡,并且是匿名函數(shù)深员,而在紅寶書(P182)中介紹過,匿名函數(shù)的執(zhí)行環(huán)境具有全局性蛙埂,所以此時的this指向全局倦畅,即打印出 1.

再深入理解一下,你知道為什么說第64行是定義了一個新函數(shù)嗎绣的?

在64行的前面插入代碼console.log(obj.foo)叠赐,你會發(fā)現(xiàn)瀏覽器會打印出一個函數(shù)表達式,也就是obj.foo是一個函數(shù)表達式屡江,第64行是把該函數(shù)表達式賦值給fooo芭概,所以此時的fooo是一個函數(shù)

上述代碼等價于

注意:此時瀏覽器打印出 2是因為70行代碼將變量重新賦值成2,覆蓋了68行的賦值盼理,即此時的a仍然是全局變量谈山。上述代碼是一個函數(shù)的獨立調用。所以此時的this指向全局宏怔。

要不要再嘗試一下奏路?現(xiàn)在把65行改成var fooo = obj.foo()

可以發(fā)現(xiàn)此時第66行報錯,這是為什么呢臊诊?聰明的同學已經(jīng)發(fā)現(xiàn)鸽粉,obj.foo()是一個函數(shù)的方法調用,此時的返回值是obj中的局部變量 2抓艳,此時的fooo是一個被聲明的變量触机,那么它就不再是一個函數(shù)的形式了,所以也就不能使用fooo()了玷或。

二儡首、傳參丟失

1,語言內置的函數(shù)傳參偏友,比如使用setTimeout()時

大家都知道蔬胯,setTimeout()的用法如下

例如:setTimeout(function(){....}, 3000);

在經(jīng)過3000ms后執(zhí)行{....}的內容,第83行代碼的執(zhí)行過程是先將obj.foo賦值給setTimeout的第一個參數(shù)位他,問題就出現(xiàn)在這里氛濒,請看前文的賦值丟失情況介紹产场,是不是同一個道理?

2舞竿,自定義函數(shù)傳參時

其實這就是第一種情況的變種京景,實際上參數(shù)傳遞就是一種隱式賦值

顯式綁定

函數(shù)的間接調用引發(fā)this的顯示綁定。

JavaScript中的函數(shù)也是對象骗奖,和其他JavaScript對象沒什么兩樣确徙,函數(shù)對象也可以包含方法,其中的兩個方法call()和apply()可以作為任何對象的方法來調用重归。兩個方法都允許顯式指定調用所需的this值米愿。

bind()是ES5中新增的方法,當在函數(shù)foo()上調動bind()方法并傳入一個對象obj作為參數(shù)鼻吮,這個方法將返回一個新的函數(shù)育苟,當然此時this也便是方法調用了,所以會指向當前對象obj椎木。

注:普通的顯式綁定無法解決隱式丟失問題

硬綁定

硬綁定是顯式綁定的一個變種违柏,固定this的指向,上例中的bind()是硬綁定的內置函數(shù)

代碼說明:

在bar函數(shù)內部手動調用foo.call(obj)香椎。因此漱竖,無論之后如何調用函數(shù)bar,它總會手動在obj上調用foo

new綁定

如果函數(shù)或者方法調用之前帶有關鍵字new畜伐,它就構成構造函數(shù)調用馍惹。對于this綁定來說,稱為new綁定玛界。

構造函數(shù)的四個步驟:

第一步:創(chuàng)建一個新對象

第二步:將構造函數(shù)的作用域賦給新對象(因此this就指向了這個新對象)

第三步:執(zhí)行構造函數(shù)中的代碼(為這個新對象添加屬性)

第四步:返回新對象

最后万矾,他們的優(yōu)先級是:new > 顯式>隱式>默認


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市慎框,隨后出現(xiàn)的幾起案子良狈,更是在濱河造成了極大的恐慌,老刑警劉巖笨枯,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件薪丁,死亡現(xiàn)場離奇詭異,居然都是意外死亡馅精,警方通過查閱死者的電腦和手機严嗜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來洲敢,“玉大人阻问,你說我怎么就攤上這事÷偌玻” “怎么了称近?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長哮塞。 經(jīng)常有香客問我刨秆,道長,這世上最難降的妖魔是什么忆畅? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任衡未,我火速辦了婚禮,結果婚禮上家凯,老公的妹妹穿的比我還像新娘缓醋。我一直安慰自己,他們只是感情好冕香,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布骑科。 她就那樣靜靜地躺著讲逛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪抗俄。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天世舰,我揣著相機與錄音动雹,去河邊找鬼。 笑死跟压,一個胖子當著我的面吹牛胰蝠,可吹牛的內容都是我干的。 我是一名探鬼主播震蒋,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼茸塞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了喷好?” 一聲冷哼從身側響起翔横,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎梗搅,沒想到半個月后禾唁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡无切,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年荡短,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哆键。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡掘托,死狀恐怖,靈堂內的尸體忽然破棺而出籍嘹,到底是詐尸還是另有隱情闪盔,我是刑警寧澤弯院,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站泪掀,受9級特大地震影響听绳,放射性物質發(fā)生泄漏。R本人自食惡果不足惜异赫,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一椅挣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧塔拳,春花似錦鼠证、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至孕荠,卻和暖如春娩鹉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背稚伍。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工弯予, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人个曙。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓锈嫩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親垦搬。 傳聞我的和親對象是個殘疾皇子呼寸,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內容