JS中的this對象詳解

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“。

    怎麼樣,你做對了嗎?

發佈了17 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章