JS中this關鍵字很常見,但是它似乎變幻莫測,讓人抓狂。這篇文章就來揭示其中的奧祕。
藉助阮一峯老師的話:它代表函數運行時,自動生成的一個內部對象,只能在函數內部使用。這句話看似平常,可是要非常注意三個字:“運行時”,這說明this關鍵字只與函數的執行環境有關,而與聲明環境沒有關係。也就是這個this到底代表的是什麼對象要等到函數運行時才知道,有點類似函數定義時的參數列表只在函數調用時才傳入真正的對象。理解了這一點對後面this關鍵字規律的掌握有很大幫助。
this關鍵字雖然會根據環境變化,但是它始終代表的是調用當前函數的那個對象。這就引出了JS中函數調用的問題。在JS中調用函數的模式可以分爲4種: 方法調用模式、函數調用模式、構造器調用模式、apply調用模式。這些模式在如何初始化關鍵參數this上存在差異。
一、方法調用模式
當函數被保存爲一個對象的屬性時,它就可稱爲這個對象的方法。當一個方法被調用時,this被綁定到這個對象上。如果調用表達式包含一個提取屬性的動作(. 或 []),那麼它被稱爲方法調用。例如:
1
2
3
4
5
6
7
8
|
var name
= "window" ; var obj
= { name:
"kxy" , sayName:
function ()
{ console.log( this .name); } }; obj.sayName();
//kxy |
sayName函數作爲對象obj的方法調用,所以函數體中的this就代表obj對象。
二、函數調用模式
當一個函數並非一個對象的屬性時,那麼它就是被當做函數來調用的。在此種模式下,this被綁定爲全局對象,在瀏覽器環境下就是window對象。例如:
1
2
3
4
5
|
var name
= "window" ; function sayName()
{ console.log( this .name); } sayName(); |
sayName以函數調用模式調用,所以函數體中的this代表window對象。
三、構造函數模式
如果在一個函數前面加上new關鍵字來調用,那麼就會創建一個連接到該函數的prototype成員的新對象,同時,this會被綁定到這個新對象上。這種情況下,這個函數就可以成爲此對象的構造函數。例如:
1
2
3
4
5
|
function Obj()
{ this .name
= "kxy" ; } var person
= new Obj(); console.log(person.name);
//kxy |
Obj作爲構造函數被調用,函數體內的this被綁定爲新創建的對象person。
四、apply調用模式
在JS中,函數也是對象,所有函數對象都有兩個方法:apply和call,這兩個方法可以讓我們構建一個參數數組傳遞給調用函數,也允許我們改變this的值。例如:
1
2
3
4
5
6
7
8
9
10
|
var name
= "window" ; var person
= { name:
"kxy" }; function sayName()
{ console.log( this .name); } sayName();
//window sayName.apply(person);
//kxy sayName.apply();
//window |
當以函數調用模式調用sayName時,this代表window;當用apply模式調用sayName,並給它傳入的第一個參數爲person時,this被綁定到person對象上。如果不給apply傳入任何參數,則this代表window。
自此,函數調用的4種模式就都介紹完了,this的綁定規律也就是以上幾種,萬變不離其宗。爲了簡單明瞭的介紹4種模式,以上的例子都比較簡單,那麼下面就跟我一起做一個稍複雜的練習,檢驗下自己是否真正掌握了this綁定對象的方法吧!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
var name
= "window" ; function showName()
{ console.log( this .name); } var person1
= { name:
"kxy" , sayName:
showName } var person2
= { name:
"Jake" , sayName:
function ()
{ var fun
= person1.sayName; fun(); } } person1.sayName();
//kxy person2.sayName();
//window |
首先心中時刻提醒自己this是在函數執行時被綁定的,不要被任何賦值語句打亂陣腳。
先看第一個執行語句:person1.sayName(); 首先確定這是方法調用模式,對象爲person1,再看sayName被賦值爲全局函數對象showName,在showName執行時,this綁定的是person1,所以結果爲”kxy”。
再看第二個執行語句:person2.sayName(); 這還是方法調用模式,對象爲person2,調用的是它的sayName方法。再看sayName函數體,發現函數體最終執行的函數是fun,fun是用函數調用模式調用的。而fun最終也被賦值爲showName函數,因爲fun是用函數調用模式調用的,所以這裏的this綁定爲window,結果爲”window“。
怎麼樣,你做對了嗎?