1. 程式人生 > >Coder Ben's Writing

Coder Ben's Writing

     JS中this關鍵字很常見,但是它似乎變幻莫測,讓人抓狂。這篇文章就來揭示其中的奧祕。


     藉助阮一峰老師的話:它代表函式執行時,自動生成的一個內部物件,只能在函式內部使用。這句話看似平常,可是要非常注意三個字:“執行時”,這說明this關鍵字只與函式的執行環境有關,而與宣告環境沒有關係。也就是這個this到底代表的是什麼物件要等到函式執行時才知道,有點類似函式定義時的引數列表只在函式呼叫時才傳入真正的物件。理解了這一點對後面this關鍵字規律的掌握有很大幫助。

     this關鍵字雖然會根據環境變化,但是它始終指向的是呼叫當前函式的那個物件。這就引出了JS中函式呼叫的問題。在JS中呼叫函式的模式可以分為4種:方法呼叫模式、函式呼叫模式、構造器呼叫模式、apply呼叫模式
。這些模式在如何初始化關鍵引數this上存在差異。

一、方法呼叫模式

     當函式被儲存為一個物件的屬性時,它就可稱為這個物件的方法。當一個方法被呼叫時,this被繫結到這個物件上。如果呼叫表示式包含一個提取屬性的動作(. 或 []),那麼它被稱為方法呼叫。例如:

var name = "window";
var obj = {
  name: "obj",
  getName: function(){
    alert(this.name);
  }
}
obj.getName(); //"obj"  

     getName函式作為物件obj的方法呼叫,所以函式體中的this就代表obj物件。


二、函式呼叫模式
   當一個函式並非一個物件的屬性時,那麼它就是被當做函式來呼叫的。在此種模式下,this被繫結為全域性物件,在瀏覽器環境下就是window物件。例如:

var name = "window";
function getName(){
  alert(this.name);
}
getName(); //"window"
 getName函式是一個單獨函式(非某物件方法),所以建立後就歸屬到了window物件之下,呼叫時this指向window。

三、建構函式模式

     如果在一個函式前面加上new關鍵字來呼叫,那麼就會建立一個連線到該函式的prototype成員的新物件,同時,this會被繫結到這個新物件上。這種情況下,這個函式就可以成為此物件的建構函式。例如:

function obj(){
  this.name = "obj";
}
var o = new obj();
alert(o.name); //"obj"
     使用new建立物件o時,在建構函式中this指向了o,因此o的name屬性被賦值為“obj”。

四、apply呼叫模式

在JS中,函式也是物件,所有函式物件都有兩個方法:apply和call,這兩個方法可以讓我們構建一個引數陣列傳遞給呼叫函式,也允許我們改變this的值。例如:

var name = "window";
var obj = {
  name : "obj"
};
function getName(){
  alert(this.name);
}
getName.apply(); //"window"
getName.apply(obj); //"obj"
    直接呼叫函式物件getName的apply方法,由於沒有引數,所以被劃歸到了全域性作用域中,this指向了window物件;

    將getName函式在obj物件上呼叫,函式體內的this也就指向了obj物件;

    自此,函式呼叫的4種模式就都介紹完了,this的繫結規律也就是以上幾種,萬變不離其宗。為了簡單明瞭的介紹4種模式,以上的例子都比較簡單,那麼下面就跟我一起做一個稍複雜的練習,檢驗下自己是否真正掌握了this繫結物件的方法吧!

var name = "window";
function printName(){
  alert(this.name);
}
var obj1 = {
  name : "obj1",
  getName : printName
};
var obj2 = {
  name : "obj2",
  getName : function(){
    var func = obj1.getName;
    func();
  }
};
obj1.getName();
obj2.getName();

     第一次是呼叫obj1物件的getName方法(函式體同printName函式),所以this指向obj1物件,輸出“obj1”;

     第二次是雖然是呼叫obj2物件的getName方法,但是其此方法的函式體內又新建了一個func函式,它是獨立的,而非obj2物件的內部方法,所以“func();”語句的執行環境是全域性作用域,this指向window物件,輸出“window”。

     怎麼樣,你做對了嗎?得意