JavaScript中this指向的深入解析

普通函數(shù)的this指向

簡單說說

首先霉祸,按照慣例,我們先舉個栗子:

var bar = 2;
function foo() {
  this.bar = 1;
  this.getBar = function() {
    console.log(this.bar);
  }
}
var test = new foo();
var getBar = test.getBar;

test.getBar();  //1
getBar();       //2

通過這個例子我們就能看到袱蜡,雖然是同一個函數(shù)丝蹭,但是實際上得到的結(jié)果卻不一樣。這個原因相信大家都能知道坪蚁。不知道的也告訴你:this其實是指向調(diào)用該函數(shù)的那個對象奔穿。那么當(dāng)我們在全局環(huán)境中調(diào)用的時候,this自然就指向了全局環(huán)境敏晤。

那么到是有個問題:this為什么會隨調(diào)用者變化而變化贱田?

這可能需要你繼續(xù)往下看看

深入說說

那么如果說深層次的理解this的指向,我覺得大概可以從數(shù)據(jù)類型講起

我們都知道茵典,棧中存放的是基本數(shù)據(jù)類型湘换,也就是StringNumber统阿、Boolean彩倚、SymbolNull扶平、Undefined這七種數(shù)據(jù)類型帆离,當(dāng)然Symbol是ES6新增的一個數(shù)據(jù)類型。那么堆中存放的就是一些引用類型了结澄,如Obejct哥谷、Function。實際上當(dāng)我們定義一個引用類型的時候麻献,js會同時定義一個地址指針指向內(nèi)存中的對象们妥。

例如:當(dāng)我們聲明一個字面量對象時候let a = {num:1};實際上a中存放的是指向{num:1}的地址

定義引用類型時

現(xiàn)在我們解析一下上面那段代碼是如何執(zhí)行的

// 在全局環(huán)境下定義一個變量bar
var bar = 2;

function foo() {
    //在foo中也聲明了一個bar
    this.bar = 1;
    
    //在foo中聲明一個getBar函數(shù)
    this.getBar = function() {
        console.log(this.bar);
    }
}

//構(gòu)造函數(shù)模式自定義對象,將foo的this賦予test
var test = new foo();

//將test中的getBar方法賦予getBar
var getBar = test.getBar;

//調(diào)用test中的getBar
test.getBar();  //1

//調(diào)用getBar
getBar();       //2

現(xiàn)在列出來一看勉吻,放佛恍然大悟监婶,終于知道為啥輸出的是不同的結(jié)果了。那么我這里倒是有幾個問題

  • 為什么調(diào)用同一個函數(shù)卻有不同的結(jié)果?
  • foo中的this是指向foo的惑惶,為什么foo中的函數(shù)可以取得外部的this煮盼?
  • 為什么this會隨調(diào)用它的對象變化而變化?

ok带污,其實要弄清楚上述問題僵控,我們需要明白一點,函數(shù)也是個引用類型鱼冀。那么我們上面講過报破,創(chuàng)建引用類型的時候會同時創(chuàng)建一個地址指針。那么我們就可以這樣理解上面的foo對象

this.png

實際上foo中的getBar只是存放了一個函數(shù)的地址而已*雷绢。那么這個函數(shù)并不是foo所私有泛烙。什么東西是foo的呢?一個值為1的bar和一個指向function() {console.log(this.bar);}函數(shù)的getBar而已翘紊。

這樣我們就不難理解蔽氨,為什么調(diào)用同一個函數(shù)會有不一樣的結(jié)果了,因為這個函數(shù)并不是foo所私有帆疟。好比內(nèi)存就是深圳鹉究,函數(shù)就只是深圳的一套房。getBar就是這套房的鑰匙踪宠。那么一開始foo這個人建好了這房子自赔,就他有這房子的鑰匙,那么當(dāng)然只有他能進出該房子柳琢,后來有一天他把鑰匙多配了一把給了window這好朋友绍妨。于是乎window也能進這套房了。給window配鑰匙的過程:var getBar = test.getBar;這里只是將該函數(shù)的地址賦給全局下的getBar而已柬脸,房子也只是一套房子他去,函數(shù)還是一個函數(shù)。

由于函數(shù)可以在不同的運行環(huán)境執(zhí)行倒堕,所以需要有一種機制灾测,能夠在函數(shù)體內(nèi)部獲得當(dāng)前的運行環(huán)境(context)。所以垦巴,this就出現(xiàn)了媳搪,它的設(shè)計目的就是在函數(shù)體內(nèi)部,指代函數(shù)當(dāng)前的運行環(huán)境骤宣。

所以當(dāng)window調(diào)用這個函數(shù)的時候秦爆,this就不是指向foo了。而是指向window憔披。this是指向他們自己等限。window的衣服不會在進了foo的房子以后就變成foo的衣服。

ok,我們現(xiàn)在再把剛剛的代碼重新注釋一下

// 在全局環(huán)境下定義一個變量bar
var bar = 2;

function foo() {
    //在foo中也聲明了一個bar
    this.bar = 1;
    
    //在foo中聲明一個getBar函數(shù)精刷,getBar存放該函數(shù)的地址
    this.getBar = function() {
        console.log(this.bar);
    }
}

//構(gòu)造函數(shù)模式自定義對象,將foo的this賦予test
var test = new foo();

//將test中的getBar方法的地址賦予全局的getBar
var getBar = test.getBar;

//調(diào)用test中的getBar函數(shù)
test.getBar();  //1

//調(diào)用getBar函數(shù)
getBar();       //2

于是乎我們就把普通的this指向弄明白了蔗候。順便還明白了堆棧的區(qū)別怒允。接下來看看不普通的函數(shù)this指向是如何的

箭頭函數(shù)this指向

箭頭函數(shù)內(nèi)沒有this,箭頭函數(shù)的this是父級函數(shù)的this

// 在全局環(huán)境下定義一個變量bar
var bar = 2;

function foo() {
    //在foo中也聲明了一個bar
    this.bar = 1;
    
    //在foo中定義一個箭頭函數(shù)锈遥,getBar存放該函數(shù)的地址
    this.getBar = () => {
        console.log(this.bar);
    }
}

//構(gòu)造函數(shù)模式自定義對象纫事,將foo的this賦予test
var test = new foo();

//將test中的getBar方法的地址賦予全局的getBar
var getBar = test.getBar;

//調(diào)用test中的getBar函數(shù)
test.getBar();  //1

//調(diào)用getBar函數(shù)
getBar();       //1

如果定義了箭頭函數(shù)的情況下,this執(zhí)行就不會隨意的改變了所灸。普通函數(shù)的this是會跟隨調(diào)用者變化丽惶,但是箭頭函數(shù)就很特別,他只會繼承父級的this爬立,而且一旦建立就不會改變了钾唬。所以在這里我們就可以看見,盡管全局下面調(diào)用getBar侠驯,但是實際上還是取到了foo的this抡秆。

因此箭頭函數(shù)不可以用來當(dāng)作構(gòu)造函數(shù)。因為它本身是沒有this的吟策!

所以箭頭函數(shù)使用的話需要與普通函數(shù)區(qū)別開這點儒士,它的this指向定義函數(shù)時候的父級。

后話

關(guān)于this就介紹到這里檩坚,如果有什么不懂的歡迎隨時提問着撩,我會隨時回答大家的問題。

那么最后匾委,成功不在一朝一夕拖叙,我們都需要努力

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市剩檀,隨后出現(xiàn)的幾起案子憋沿,更是在濱河造成了極大的恐慌,老刑警劉巖沪猴,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件辐啄,死亡現(xiàn)場離奇詭異,居然都是意外死亡运嗜,警方通過查閱死者的電腦和手機壶辜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來担租,“玉大人砸民,你說我怎么就攤上這事。” “怎么了岭参?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵反惕,是天一觀的道長。 經(jīng)常有香客問我演侯,道長姿染,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任秒际,我火速辦了婚禮悬赏,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘娄徊。我一直安慰自己闽颇,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布寄锐。 她就那樣靜靜地躺著兵多,像睡著了一般。 火紅的嫁衣襯著肌膚如雪橄仆。 梳的紋絲不亂的頭發(fā)上中鼠,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天,我揣著相機與錄音沿癞,去河邊找鬼援雇。 笑死,一個胖子當(dāng)著我的面吹牛椎扬,可吹牛的內(nèi)容都是我干的惫搏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼蚕涤,長吁一口氣:“原來是場噩夢啊……” “哼筐赔!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起揖铜,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤茴丰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后天吓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贿肩,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年龄寞,在試婚紗的時候發(fā)現(xiàn)自己被綠了汰规。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡物邑,死狀恐怖溜哮,靈堂內(nèi)的尸體忽然破棺而出滔金,到底是詐尸還是另有隱情,我是刑警寧澤茂嗓,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布餐茵,位于F島的核電站,受9級特大地震影響述吸,放射性物質(zhì)發(fā)生泄漏钟病。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一刚梭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧票唆,春花似錦朴读、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至簿煌,卻和暖如春氮唯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背姨伟。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工惩琉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人夺荒。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓瞒渠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親技扼。 傳聞我的和親對象是個殘疾皇子伍玖,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,060評論 2 355

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