this关键字
this關鍵字在JavaScript裡的具體含義完全不同於C#或者Java這種基於類的編程語言,所以參考後者來理解前者只會更加迷惑。在JavaScript裡並不存在C#中的類,也就不存在類的實例,所以this不可能指向那樣一個東西。
JavaScript裡的this究竟該怎樣解釋,目前我還沒有發現任何術語可以簡單地說明並且不具歧義性,很多人把它稱為函數執行時的上下文(context),但是JS的術語裡context其實是用來指JS引擎給被調用函數維護的一組數據,這個context本身不是對JS代碼可見的,是引擎內部的實現,this所指向的內容則是這組數據裡包含的一個項目,從最廣義的角度解讀context的話,要把this說成是執行函數的上下文也依然不夠嚴格,我覺得它也只能是其中的一部分,所以我只能說它指向著一個特定的函數的上下文,如果沒有它的話,想引用這個上下文裡的屬性確實有點難度。
this到底指向什麼,要取決於該函數是怎麼被調用的(基本上跟它如何被定義的關係不大),在不同的調用情況裡,對this進行的綁定方法有所不同,這種綁定是動態的,完全在函數被調用時才決定的。那麼現在來盤點下在JavaScript裡,函數究竟有哪些被調用的方式:
- 作為一個獨立的函數被調用,不論是在全局作用域裡,或者在局域作用域裡。
- 被作為一個對象的方法被調用。
- 作為一個事件的處理函數被綁定在該事件上(比如通過addEventListener),當該事件觸發時被自動調用。
- 作為回調函數,以參數的形式傳給其他函數(比如setTimeout),再被調用。
- 通過apply或者call函數被調用。
- 作為“構造函數”,放在new關鍵字後面被調用。
作為一個獨立的函數被調用(stand alone)
上面的截圖裡展示的是最基本的情況,做一點微弱的變動,它可以有不同的形式:
其實這個調用模式只是下一個將要講到的調用模式的一種特例,之後會再回來說這個問題。
作為一個對象的方法被調用(member method)
在JavaScript裡,並沒有真正意義上的“類,”面向對象的機制是通過叫“原型鏈”的東西實現的,所以在JS裡,你可以給一個對象定義成員方法的方式就有很多種,而且也很靈活。從編碼風格來看,你常見到的會有下面幾種(實際上並不僅限於這幾種方法):
在上面這三個例子裡,freud函數都是以lacan對象的方法被調用的,所以輸出的dream是lacan對象內的那個成員屬性,而不是全局作用域那個。
作為一個事件的處理函數(handler)
從這裡開始,演示代碼要變複雜一些。為了簡化問題,我使用HTML5裡的一個新功能:標籤裡的自定義屬性(custom attribute)。先有如下html代碼:
<!DOCTYPE html>
<HEAD>
<TITLE></TITLE>
<SCRIPT src="this-explicit-binding-1.js"></SCRIPT>
</HEAD>
<BODY>
<button id="lacan" data-dream="sleep protector">Try this</button>
</BODY>
</HTML>
有一個簡單的按鈕,給它一個id這樣JS就可以在DOM樹裡訪問到它,然後再添加一個data-*屬性,這樣就可以在JS裡通過dataset屬性訪問這些自定義的標籤屬性。我要展示的問題是在JS裡給按鈕lacan綁定一個處理點擊事件的函數,當lacan被點擊,這個函數執行時,函數內的this其實是指向lacan按鈕對象本身的。
var jung;
var dream = 'supernatural communication';
window.onload = function() {
jung = document.getElementById("lacan");
jung.addEventListener("click", function(){
console.log(this.dataset.dream);
});
};
Note: 如果直接把var jung = document.getElementById("lacan");寫在window.onload外面是不行的,因為在它被執行的時候,整個HTML頁面還沒有被加載完成,DOM樹沒有被生成,所以jung將會是null。 |
Ref: http://stackoverflow.com/questions/588040/window-onload-vs-document-onload/28144681 https://developer.mozilla.org/en/docs/Web/Guide/HTML/Using_data_attributes http://www.w3schools.com/tags/att_global_data.asp http://www.w3schools.com/jsref/met_element_addeventlistener.asp |