五分鐘讓你了解ES5和ES6中this指向問題

首先對this的下個(gè)定義:this是在執(zhí)行上下文創(chuàng)建時(shí)確定的一個(gè)在執(zhí)行過程中不可更改的變量疼鸟。

this只在函數(shù)調(diào)用階段確定,也就是執(zhí)行上下文創(chuàng)建的階段進(jìn)行賦值柏蘑,保存在變量對象中幸冻。這個(gè)特性也導(dǎo)致了this的多變性:即當(dāng)函數(shù)在不同的調(diào)用方式下都可能會(huì)導(dǎo)致this的值不同:

vara =1;functionfun(){? 'use strict';vara =2;returnthis.a;}fun();//報(bào)錯(cuò) Cannot read property 'a' of undefined

嚴(yán)格模式下,this指向undefined;??

vara =1;functionfun(){vara =2;returnthis.a;}fun();//1

即在不同模式下之所以有不同表現(xiàn)咳焚,就是因?yàn)閠his在嚴(yán)格模式洽损,非嚴(yán)格模式下的不同。??

結(jié)論:當(dāng)函數(shù)獨(dú)立調(diào)用的時(shí)候革半,在嚴(yán)格模式下它的this指向undefined碑定,在非嚴(yán)格模式下,當(dāng)this指向undefined的時(shí)候又官,自動(dòng)指向全局對象(瀏覽器中就是window)

在全局環(huán)境下延刘,this就是指向自己:

this.a =1;varb =1;c =1;console.log(this===window)//true//這三種都能得到想要的結(jié)果,全局上下文的變量對象中存在這三個(gè)變量

當(dāng)this不在函數(shù)中用的時(shí)候六敬,this還是指向了window:

vara =100;varobj = {a:1,b:this.a +1}functionfun(){varobj = {a:1,c:this.a +2//嚴(yán)格模式下這塊報(bào)錯(cuò) Cannot read property 'a' of undefined}returnobj.c;}console.log(fun());//102console.log(obj.b);//101

結(jié)論:當(dāng)obj在全局聲明的時(shí)候碘赖,obj內(nèi)部屬性中的this指向全局對象,當(dāng)obj在一個(gè)函數(shù)中聲明的時(shí)候,嚴(yán)格模式下this會(huì)指向undefined崖疤,非嚴(yán)格模式自動(dòng)轉(zhuǎn)為指向全局對象秘车。

現(xiàn)在知道了嚴(yán)格模式和非嚴(yán)格模式下this的區(qū)別,然而我們?nèi)粘?yīng)用最多的還是在函數(shù)中用this劫哼,上面也說過了this在函數(shù)的不同調(diào)用方式還有區(qū)別叮趴,那么函數(shù)的調(diào)用方式都有哪些呢?四種:

在全局環(huán)境或是普通函數(shù)中直接調(diào)用

作為對象的方法

使用apply和call

作為構(gòu)造函數(shù)

下面分別就四種情況展開:

直接調(diào)用

fun函數(shù)雖然在obj.b方法中定義权烧,但它還是一個(gè)普通函數(shù)眯亦,直接調(diào)用在非嚴(yán)格模式下指向undefined,又自動(dòng)指向了全局對象般码,正如預(yù)料妻率,嚴(yán)格模式會(huì)報(bào)錯(cuò)undefined.a不成立,a未定義板祝。

vara =1;varobj? =? {a:2,b:function(){functionfun(){returnthis.a? ? ? ? }console.log(fun());? ? }} obj.b();//1

作為對象的方法

b所引用的匿名函數(shù)作為obj的一個(gè)方法調(diào)用宫静,這時(shí)候this指向調(diào)用它的對象。這里也就是obj:

vara =1;varobj = {a:2,b:function(){returnthis.a;? }}console.log(obj.b())//2

那么如果b方法不作為對象方法調(diào)用:

vara =1;varobj = {a:2,b:function(){returnthis.a;? }}vart = obj.b;console.log(t());//1

如上券时,t函數(shù)執(zhí)行結(jié)果竟然是全局變量1孤里,為啥呢?這就涉及Javascript的內(nèi)存空間了橘洞,就是說捌袜,obj對象的b屬性存儲(chǔ)的是對該匿名函數(shù)的一個(gè)引用,可以理解為一個(gè)指針炸枣。當(dāng)賦值給t的時(shí)候虏等,并沒有單獨(dú)開辟內(nèi)存空間存儲(chǔ)新的函數(shù),而是讓t存儲(chǔ)了一個(gè)指針适肠,該指針指向這個(gè)函數(shù)霍衫。相當(dāng)于執(zhí)行了這么一段偽代碼:

vara =1;functionfun(){//此函數(shù)存儲(chǔ)在堆中returnthis.a;}varobj = {a:2,b: fun//b指向fun函數(shù)}vart = fun;//變量t指向fun函數(shù)console.log(t());//1

此時(shí)的t就是一個(gè)指向fun函數(shù)的指針,調(diào)用t迂猴,相當(dāng)于直接調(diào)用fun慕淡,套用以上規(guī)則,打印出來1自然很好理解了沸毁。

使用apply,call

這是個(gè)萬能公式,實(shí)際上上面直接調(diào)用的代碼傻寂,我們可以看成這樣的:

functionfun(){returnthis.a;}fun();//1//嚴(yán)格模式fun.call(undefined)//非嚴(yán)格模式fun.call(window)

這時(shí)候我們就可以解釋下息尺,為啥說在非嚴(yán)格模式下,當(dāng)函數(shù)this指向undefined的時(shí)候疾掰,會(huì)自動(dòng)指向全局對象搂誉,如上,在非嚴(yán)格模式下静檬,當(dāng)調(diào)用fun.call(undefined)的時(shí)候打印出來的依舊是1炭懊,就是最好的證據(jù)并级。

為啥說是萬能公式呢?再看函數(shù)作為對象的方法調(diào)用:

vara =1;varobj = {a:2,b:function(){returnthis.a;? }}obj.b()obj.b.call(obj)

如上侮腹,是不是很強(qiáng)大嘲碧,可以理解為其它兩種都是這個(gè)方法的語法糖罷了,那么apply和call是不是真的萬能的呢父阻?并不是愈涩,ES6的箭頭函數(shù)就是特例,因?yàn)榧^函數(shù)的this不是在調(diào)用時(shí)候確定的加矛,這也就是為啥說箭頭函數(shù)好用的原因之一履婉,因?yàn)樗膖his固定不會(huì)變來變?nèi)サ牧恕jP(guān)于箭頭函數(shù)的this我們稍后再說斟览。

作為構(gòu)造函數(shù)

何為構(gòu)造函數(shù)毁腿?所謂構(gòu)造函數(shù)就是用來new對象的函數(shù),像Function苛茂、Object已烤、Array、Date等都是全局定義的構(gòu)造函數(shù)味悄。其實(shí)每一個(gè)函數(shù)都可以new對象草戈,那些批量生產(chǎn)我們需要的對象的函數(shù)就叫它構(gòu)造函數(shù)罷了。注意侍瑟,構(gòu)造函數(shù)首字母記得大寫唐片。

functionFun(){this.name ='Lili';this.age =21;this.sex ='woman';this.run =function(){returnthis.name +'正在跑步';? }}Fun.prototype = {contructor: Fun,say:function(){returnthis.name +'正在說話';? }}varf =newFun();f.run();//Lili正在跑步f.say();//Lili正在說話

如上,如果函數(shù)作為構(gòu)造函數(shù)用涨颜,那么其中的this就代表它即將new出來的對象费韭。為啥呢?new做了啥呢庭瑰?

偽代碼如下:

functionFun(){//new做的事情varobj = {};? obj.__proto__ = Fun.prototype;//Base為構(gòu)造函數(shù)obj.name ='Lili';? ...//一系列賦值以及更多的事returnobj}

也就是說new做了下面這些事:

創(chuàng)建一個(gè)臨時(shí)對象

給臨時(shí)對象綁定原型

給臨時(shí)對象對應(yīng)屬性賦值

將臨時(shí)對象return

也就是說new其實(shí)就是個(gè)語法糖星持,this之所以指向臨時(shí)對象還是沒逃脫上面說的幾種情況。

當(dāng)然如果直接調(diào)用Fun(),如下:

functionFun(){this.name ='Damonre';this.age =21;this.sex ='man';this.run =function(){returnthis.name +'正在跑步';? }}Fun();console.log(window)

其實(shí)就是直接調(diào)用一個(gè)函數(shù)弹灭,this在非嚴(yán)格模式下指向window督暂,你可以在window對象找到所有的變量。

另外還有一點(diǎn)穷吮,prototype對象的方法的this指向?qū)嵗龑ο舐呶蹋驗(yàn)閷?shí)例對象的proto已經(jīng)指向了原型函數(shù)的prototype。這就涉及原型鏈的知識(shí)了捡鱼,即方法會(huì)沿著對象的原型鏈進(jìn)行查找八回。

箭頭函數(shù)

剛剛提到了箭頭函數(shù)是一個(gè)不可以用call和apply改變this的典型。

我們看下面這個(gè)例子:

vara =1;varobj = {a:2};varfun =()=>console.log(this.a);fun();//1fun.call(obj)//1

以上,兩次調(diào)用都是1缠诅。

那么箭頭函數(shù)的this是怎么確定的呢溶浴?箭頭函數(shù)會(huì)捕獲其所在上下文的 this 值,作為自己的 this 值管引,也就是說箭頭函數(shù)的this在詞法層面就完成了綁定士败。apply,call方法只是傳入?yún)?shù)汉匙,卻改不了this拱烁。

vara =1;varobj = {a:2};functionfun(){vara =3;letf =()=>console.log(this.a);? ? ? f();};fun();//1fun.call(obj);//2

如上,fun直接調(diào)用噩翠,fun的上下文中的this值為window戏自,注意,這個(gè)地方有點(diǎn)繞伤锚。fun的上下文就是此箭頭函數(shù)所在的上下文擅笔,因此此時(shí)f的this為fun的this也就是window。當(dāng)fun.call(obj)再次調(diào)用的時(shí)候屯援,新的上下文創(chuàng)建猛们,fun此時(shí)的this為obj,也就是箭頭函數(shù)的this值狞洋。

再來一個(gè)例子:

functionFun(){this.name ='Damonare';}Fun.prototype.say =()=>{console.log(this);}varf =newFun();f.say();//window

有的同學(xué)看到這個(gè)例子會(huì)很懵弯淘,感覺上this應(yīng)該指向f這個(gè)實(shí)例對象啊。不是的吉懊,此時(shí)的箭頭函數(shù)所在的上下文是proto所在的上下文也就是Object函數(shù)的上下文庐橙,而Object的this值就是全局對象。

那么再來一個(gè)例子:

functionFun(){this.name ='Damonare';this.say =()=>{console.log(this);? ? }}varf =newFun();f.say();//Fun的實(shí)例對象

如上借嗽,this.say所在的上下文态鳖,此時(shí)箭頭函數(shù)所在的上下文就變成了Fun的上下文環(huán)境,而因?yàn)樯厦嬲f過當(dāng)函數(shù)作為構(gòu)造函數(shù)調(diào)用的時(shí)候(也就是new的作用)上下文環(huán)境的this指向?qū)嵗龑ο蟆?/p>

作者:未來的IT女神

鏈接:http://www.reibang.com/p/77cff23936b4

來源:簡書

簡書著作權(quán)歸作者所有恶导,任何形式的轉(zhuǎn)載都請聯(lián)系作者獲得授權(quán)并注明出處浆竭。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市惨寿,隨后出現(xiàn)的幾起案子邦泄,更是在濱河造成了極大的恐慌,老刑警劉巖裂垦,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虎韵,死亡現(xiàn)場離奇詭異,居然都是意外死亡缸废,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來企量,“玉大人测萎,你說我怎么就攤上這事〗旃” “怎么了硅瞧?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長恕汇。 經(jīng)常有香客問我腕唧,道長,這世上最難降的妖魔是什么瘾英? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任枣接,我火速辦了婚禮,結(jié)果婚禮上缺谴,老公的妹妹穿的比我還像新娘但惶。我一直安慰自己,他們只是感情好湿蛔,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布膀曾。 她就那樣靜靜地躺著,像睡著了一般阳啥。 火紅的嫁衣襯著肌膚如雪牌废。 梳的紋絲不亂的頭發(fā)上蔽莱,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼侵贵。 笑死,一個(gè)胖子當(dāng)著我的面吹牛笆制,可吹牛的內(nèi)容都是我干的氮墨。 我是一名探鬼主播,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼栗弟,長吁一口氣:“原來是場噩夢啊……” “哼污筷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起乍赫,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤瓣蛀,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后雷厂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體惋增,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年改鲫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了诈皿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片林束。...
    茶點(diǎn)故事閱讀 40,852評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖稽亏,靈堂內(nèi)的尸體忽然破棺而出壶冒,到底是詐尸還是另有隱情,我是刑警寧澤截歉,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布胖腾,位于F島的核電站,受9級特大地震影響瘪松,放射性物質(zhì)發(fā)生泄漏咸作。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一宵睦、第九天 我趴在偏房一處隱蔽的房頂上張望记罚。 院中可真熱鬧,春花似錦状飞、人聲如沸毫胜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽酵使。三九已至,卻和暖如春焙糟,著一層夾襖步出監(jiān)牢的瞬間口渔,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工穿撮, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留缺脉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓悦穿,卻偏偏與公主長得像攻礼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子栗柒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,851評論 2 361

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

  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line)礁扮,也就是一...
    悟名先生閱讀 4,153評論 0 13
  • 函數(shù)和對象 1、函數(shù) 1.1 函數(shù)概述 函數(shù)對于任何一門語言來說都是核心的概念瞬沦。通過函數(shù)可以封裝任意多條語句太伊,而且...
    道無虛閱讀 4,585評論 0 5
  • 前 言 學(xué)過程序語言的都知道,我們的程序語言進(jìn)化是從“面向機(jī)器”逛钻、到“面向過程”僚焦、再到“面向?qū)ο蟆币徊讲降陌l(fā)展而來...
    小風(fēng)飛魚閱讀 521評論 0 9
  • 時(shí)間過得真快,這兩只小烏龜轉(zhuǎn)眼來到我們家就十多天了曙痘。 去年年底芳悲,一個(gè)同事就說要送兩只烏龜給我們小孩玩立肘,于是我們孩子...
    西瓜甜甜啦閱讀 528評論 6 22
  • 【七律(新韻)】 感懷 -文/大漠 斜陽一抹映高臺(tái),幾片閑云淡淡來芭概。 煮酒一壺今欲醉赛不,放歌幾曲寄心懷。 年年獨(dú)自追...
    大漠qxy閱讀 210評論 13 0