原文地址:深入理解閉包(三)——確定this指向
我們在前面說過,在執(zhí)行上下文創(chuàng)建過程中做了三件事:創(chuàng)建變量對象,生成作用域鏈,確定this指向。今天我們就來探討一下this指向的問題。首先先回顧一下我們執(zhí)行上下文的生命周期圖:

執(zhí)行上下文是函數(shù)被調(diào)用時創(chuàng)建的,創(chuàng)建過程包括確定this指向,所以this的指向是在函數(shù)被調(diào)用時確定的。
我們知道,this對象是在運行時基于函數(shù)的執(zhí)行環(huán)境綁定的:在全局環(huán)境中,this指向window,當(dāng)函數(shù)被作為某個對象的方法調(diào)用時,this指向那個對象。不過實際情況中往往沒有那么好判斷,今天我們就來梳理一下。
全局對象中的this
在全局環(huán)境下,this永遠(yuǎn)指向window。
console.log(this); //window
函數(shù)中的this
this指向調(diào)用這個函數(shù)的對象。
var a = 10;
function test() {
var a = 20;
console.log(this.a);
}
test(); //10
由于函數(shù)test是被全局對象(window)調(diào)用的,因此函數(shù)內(nèi)部的this指向window。
var a = 20;
var obj = {
a: 10,
b:this.a,
fn: function () {
return this.a;
}
}
console.log(obj.fn()); //10
console.log(obj.b); //20
由于函數(shù)fn是被對象obj調(diào)用的,因此函數(shù)fn內(nèi)部的this指向?qū)ο髈bj。
另外,由于obj不是個函數(shù),不適合上面的規(guī)則,我們要單獨討論,如果obj對象在全局創(chuàng)建,那么obj里面的this指向window。
構(gòu)造函數(shù)
構(gòu)造函數(shù)和其他函數(shù)的唯一區(qū)別,就是他們的調(diào)用方式不同。任何函數(shù),只要通過new操作符來調(diào)用,那它就可以作為構(gòu)造函數(shù),調(diào)用時經(jīng)歷以下四個步驟:
- 創(chuàng)建一個新對象;
- 將構(gòu)造函數(shù)的作用域賦給新對象(因此this就指向了這個新對象);
- 執(zhí)行構(gòu)造函數(shù)中的代碼(為這個新對象添加屬性);
- 返回新對象。
function Test() {
this.a = 1;
console.log(this.a); //1
}
var fun = new Test();
console.log(fun.a); //1
創(chuàng)建新對象new Test()后,this指向這個新對象,然后為這個新對象添加屬性a = 1,再執(zhí)行console.log(this.a),此時輸出的就是剛添加的a值。返回這個新對象傳遞給了實例對象fun,此時this指向了實例fun,因此fun.a也為1。
函數(shù)用call或apply調(diào)用
我們可以利用call或apply手動設(shè)置this的指向,這兩個方法的第一個參數(shù)都是this將要指向的對象,后面的參數(shù),都是向?qū)⒁獔?zhí)行的函數(shù)傳遞參數(shù)。其中call以一個一個的形式傳遞,apply以數(shù)組的形式傳遞,這是他們唯一的不同。
var obj = {
num: 10
}
function test(a, b) {
console.log(this.num + a + b);
}
test(20,30); //NaN
test.call(obj, 20, 30); // 60
test.apply(obj, [20, 30]); // 60
這個例子很容易理解,本來調(diào)用test函數(shù)this指向全局對象,是無法訪問到obj對象中的num的,但是利用call和apply方法將this指向了obj對象,所以可以順利輸出。
以上就是我目前知道的關(guān)于this指向的幾種情況,以后可能會再補(bǔ)充。