你不知道的JavaScript之this

this 不指向函數(shù)本身粘优。

人們很容易把this 理解成指向函數(shù)自身菩暗,事實(shí)上肴敛,this 并不像我們所想的那樣指向函數(shù)本身璃哟。我們通過(guò)下面這段代碼來(lái)解釋為什么this 并是指向函數(shù)本身。

function foo(num) {
console.log( "foo: " + num );
// 記錄foo 被調(diào)用的次數(shù)
this.count++;
}
foo.count = 0;
var i;
for (i=0; i<10; i++) {
if (i > 5) {
foo( i );
}
}
// foo: 6
// foo: 7
// foo: 8
// foo: 9
// foo 被調(diào)用了多少次产艾?
console.log( foo.count ); // 0

那么this.count++這個(gè)語(yǔ)句執(zhí)行結(jié)果去了哪呢疤剑,其實(shí),這里的this指向了全局對(duì)象闷堡,此時(shí)this.count值為NaN隘膘,因?yàn)樵谌謱?duì)象中,由于不存在count變量杠览,JavaScript會(huì)為我們自動(dòng)創(chuàng)建一個(gè)名為count的變量弯菊,其初始值為”undefied“,因此進(jìn)行++操作后踱阿,this.count值變成了NaN

this 不一定指向函數(shù)的作用域

第二種常見(jiàn)的誤解是管钳,this 指向函數(shù)的作用域。在某種情況下它是正確的软舌,但是在其他情況下它卻是錯(cuò)誤的才漆。

事實(shí)上,this 在任何情況下都不指向函數(shù)的詞法作用域佛点。在JavaScript 內(nèi)部醇滥,作用域確實(shí)和對(duì)象類似,可見(jiàn)的標(biāo)識(shí)符都是它的屬性。但是作用域“對(duì)象”無(wú)法通過(guò)JavaScript代碼訪問(wèn)腺办,它存在于JavaScript 引擎內(nèi)部焰手。

function foo() {
    var a = 2;
    this.bar();
}
function bar() {
    console.log( this.a );
}
foo(); // ReferenceError: a is not defined

首先,這段代碼試圖通過(guò)this.bar() 來(lái)引用bar() 函數(shù)怀喉。調(diào)用bar() 最自然的方法是省略前面的this,直接使用詞法引用標(biāo)識(shí)符船响。

此外躬拢,編寫(xiě)這段代碼的開(kāi)發(fā)者還試圖使用this 聯(lián)通foo() 和bar() 的詞法作用域,從而讓bar() 可以訪問(wèn)foo() 作用域里的變量a见间。這是不可能實(shí)現(xiàn)的聊闯,你不能使用this 來(lái)引用一個(gè)詞法作用域內(nèi)部的東西。

每當(dāng)你想要把this 和詞法作用域的查找混合使用時(shí)米诉,一定要提醒自己菱蔬,這是無(wú)法實(shí)現(xiàn)的

this的綁定

this 的綁定和函數(shù)聲明的位置沒(méi)有任何關(guān)系,只取決于函數(shù)的調(diào)用方式史侣。當(dāng)一個(gè)函數(shù)被調(diào)用時(shí)拴泌,會(huì)創(chuàng)建一個(gè)活動(dòng)記錄(有時(shí)候也稱為執(zhí)行上下文)。這個(gè)記錄會(huì)包含函數(shù)在哪里被調(diào)用(調(diào)用棧)惊橱、函數(shù)的調(diào)用方法蚪腐、傳入的參數(shù)等信息。this 就是記錄的其中一個(gè)屬性税朴,會(huì)在函數(shù)執(zhí)行的過(guò)程中用到回季。

1、默認(rèn)綁定

獨(dú)立函數(shù)調(diào)用是最常用的函數(shù)調(diào)用類型正林∨菀唬可以把這條規(guī)則看作是無(wú)法應(yīng)用其他規(guī)則時(shí)的默認(rèn)規(guī)則。此時(shí)觅廓,this 默認(rèn)指向全局對(duì)象鼻忠。需要注意的是,在全局作用域中聲明的變量(var a = 2)就是全局對(duì)象的一個(gè)同名屬性哪亿,它們本質(zhì)上就是同一個(gè)東西粥烁。

function foo() {
    console.log( this.a );
}
var a = 2;
foo(); // 2

如果使用嚴(yán)格模式(strict mode),那么全局對(duì)象將無(wú)法使用默認(rèn)綁定蝇棉,因此this 會(huì)綁定到undefined:

function foo() {
    "use strict";
    console.log( this.a );
}
var a = 2;
foo(); // TypeError: this is undefined

2讨阻、隱式綁定

隱式綁定考慮的是調(diào)用位置是否有上下文對(duì)象,或者說(shuō)是否被某個(gè)對(duì)象擁有或者包含篡殷,不過(guò)這種說(shuō)法可能會(huì)造成一些誤導(dǎo)钝吮。換句話說(shuō),就是某個(gè)函數(shù)被某個(gè)對(duì)象所擁有,則這個(gè)函數(shù)中的this一般情況下指向這個(gè)對(duì)象奇瘦。

function foo() {
    console.log( this.a );
}
var obj = {
    a: 2,
    foo: foo
};
obj.foo(); // 2

需要注意的是:foo()的聲明方式棘催,無(wú)論是直接在obj 中定義還是先定義再添加為引用屬性,這個(gè)函數(shù)嚴(yán)格來(lái)說(shuō)都不屬于obj 對(duì)象耳标。然而醇坝,調(diào)用位置會(huì)使用obj 上下文來(lái)引用函數(shù),因此你可以說(shuō)函數(shù)被調(diào)用時(shí)obj 對(duì)象“擁有”或者“包含”它次坡。

需要注意的是呼猪,對(duì)象屬性引用鏈中只有最頂層或者說(shuō)最后一層會(huì)影響調(diào)用位置。比如:

function foo() {
    console.log( this.a );
}
var obj2 = {
    a: 42,
    foo: foo
};
var obj1 = {
    a: 2,
    obj2: obj2
};
obj1.obj2.foo(); // 42

隱式丟失:下面代碼中砸琅,雖然bar 是obj.foo 的一個(gè)引用宋距,但是實(shí)際上,它引用的是foo 函數(shù)本身症脂,因此此時(shí)的bar() 其實(shí)是一個(gè)不帶任何修飾的函數(shù)調(diào)用谚赎,因此應(yīng)用了默認(rèn)綁定。

function foo() {
    console.log( this.a );
}
var obj = {
    a: 2,
    foo: foo
};
var bar = obj.foo; // 函數(shù)別名诱篷!
var a = "oops, global"; // a 是全局對(duì)象的屬性
bar(); // "oops, global"

再看一個(gè)例子:

function foo() {
    console.log( this.a );
}
function doFoo(fn) {
    // fn 其實(shí)引用的是foo
    fn(); // <-- 調(diào)用位置壶唤!
}
var obj = {
    a: 2,
    foo: foo
};
var a = "oops, global"; // a 是全局對(duì)象的屬性
doFoo( obj.foo ); // "oops, global"

參數(shù)傳遞其實(shí)就是一種隱式賦值,因此我們傳入函數(shù)時(shí)也會(huì)被隱式賦值兴蒸,所以結(jié)果和上一個(gè)例子一樣视粮。

3、顯式綁定

通過(guò)apply橙凳、call蕾殴、bind將this綁定到特定對(duì)象上,雖然bind可綁定到null上岛啸,但十分不推薦

4钓觉、new綁定

使用new 來(lái)調(diào)用函數(shù),或者說(shuō)發(fā)生構(gòu)造函數(shù)調(diào)用時(shí)坚踩,會(huì)自動(dòng)執(zhí)行下面的操作:

  1. 創(chuàng)建(或者說(shuō)構(gòu)造)一個(gè)全新的對(duì)象荡灾。
  2. 這個(gè)新對(duì)象會(huì)被執(zhí)行[[ 原型]] 連接。
  3. 這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的this瞬铸。
  4. 如果函數(shù)沒(méi)有返回其他對(duì)象批幌,那么new 表達(dá)式中的函數(shù)調(diào)用會(huì)自動(dòng)返回這個(gè)新對(duì)象。
function foo(a) {
this.a = a;
}
var bar = new foo(2);
console.log( bar.a ); // 2

使用new 來(lái)調(diào)用foo(..) 時(shí)嗓节,我們會(huì)構(gòu)造一個(gè)新對(duì)象并把它綁定到foo(..) 調(diào)用中的this上荧缘。new 是最后一種可以影響函數(shù)調(diào)用時(shí)this 綁定行為的方法,我們稱之為new 綁定拦宣。

優(yōu)先級(jí)

new綁定>顯式綁定>隱式綁定>默認(rèn)綁定

整理:《你不知道的JavaScript(上卷)》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末截粗,一起剝皮案震驚了整個(gè)濱河市信姓,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌绸罗,老刑警劉巖意推,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異珊蟀,居然都是意外死亡菊值,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門系洛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)俊性,“玉大人,你說(shuō)我怎么就攤上這事描扯。” “怎么了趟薄?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵绽诚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我杭煎,道長(zhǎng)恩够,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任羡铲,我火速辦了婚禮蜂桶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘也切。我一直安慰自己扑媚,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布雷恃。 她就那樣靜靜地躺著疆股,像睡著了一般。 火紅的嫁衣襯著肌膚如雪倒槐。 梳的紋絲不亂的頭發(fā)上旬痹,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音讨越,去河邊找鬼两残。 笑死,一個(gè)胖子當(dāng)著我的面吹牛把跨,可吹牛的內(nèi)容都是我干的人弓。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼节猿,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼票从!你這毒婦竟也來(lái)了漫雕?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤峰鄙,失蹤者是張志新(化名)和其女友劉穎浸间,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體吟榴,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡魁蒜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吩翻。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兜看。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖狭瞎,靈堂內(nèi)的尸體忽然破棺而出细移,到底是詐尸還是另有隱情,我是刑警寧澤熊锭,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布弧轧,位于F島的核電站,受9級(jí)特大地震影響碗殷,放射性物質(zhì)發(fā)生泄漏精绎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一锌妻、第九天 我趴在偏房一處隱蔽的房頂上張望代乃。 院中可真熱鬧,春花似錦仿粹、人聲如沸搁吓。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)擎浴。三九已至,卻和暖如春毒涧,著一層夾襖步出監(jiān)牢的瞬間贮预,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工契讲, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仿吞,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓捡偏,卻偏偏與公主長(zhǎng)得像唤冈,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子银伟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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