簡介
1.引用型別(Reference type)
引用型別是javascript中一種內部型別。它主要是當做一個指涉,代替一個變數或函數,當然在需要真實值時,又可以透過它來尋找到真實值。
2.引用類型的結構
引用類型的值時由兩部分構成,一是引用類型的值指代的對象的所屬對象,這裡我們姑且把它叫做base,二是base中的指涉物件的物件名稱。用偽代碼來表示:
3.使用情境
引用類型的使用情境有二:
標示符是變數名,函數名,函數參數名和全域物件中未識別的屬性名。
(2)在處理一個屬性存取器時
var foo = 10;
{}};
var barReference = { };
這裡還是有必要解釋一下base,在javascript中所有對像或函數都有所屬對象,看過我前面文章的人都知道,在每個執行上下文有個變數對象專門來管理這個執行上下文中的變數或者函數。
所以,當處理標示符時:
在全域脈絡中,毋庸置疑,base === globalVO === gloabal
在函數的執行上下文中,base === VO/AO
但處理物件屬性是:
var base = GetBase(value);
var base = GetBase(value);
那我們什麼時候需要取得引用型別的真正值呢?
一般是在引用型別需要進行賦值、參與運算或被呼叫是需要透過GetValue方法取得真正值。 (注意:透過GetValue取得的物件不再是引用型別)
引用類型與this的關係
引用類型主要是跟函數上下文中的this指向關係密切,且不同時候看起來還差異挺大,所有我們才引出引用類型來專門解釋函數上下文中this的表現。
函數上下文中決定this值的通用規則如下:
在一個函數上下文中,this由呼叫者提供,由呼叫函數的方式決定。如果呼叫括號()的左邊是引用類型的值,this將設為引用型別值的base物件(base object),在其他情況下(與參考型別不同的任何其它屬性),這個值為null。不過,實際上不存在this的值為null的情況,因為當this的值為null的時候,其值會被隱式轉換為全域物件。註:第5版的ECMAScript中,已經不強迫轉換成全域變數了,而是賦值為undefined。
下面我們依照呼叫括號左邊不同分成三種情況來討論:
(1)呼叫括號左邊是引用型別的值
這無需做過多分析,base物件就是this值,找到base即可。如果是全域變數下申明的,那就指向全域物件。
myObject.foo(); //毫無疑問,這個foo的base是myObject,故foo方法中的this指向myObject。
(2)呼叫括號左邊是引用型別的值,不過這個值為null
當一個內部函數被呼叫時,這個內部函數的base應該是當前執行上下文中活動對象(OA),但是在javascript內部在OA作為base時,都當做null處理,javascript當然不允許this為null的情況發生,所有就將base設定為global物件(這是前文this函數呼叫模式中設計錯誤的來源)。所以在這情況下,this都指向全域物件。
console.log(this);
}
};
foo.bar(); // Reference, OK => foo
(foo.bar)(); // Reference, OK => foo
(foo.bar = foo.bar )(); // global
(false || foo.bar)(); // global
(foo.bar, foo.bar)(); // global
當呼叫括號的左邊不是引用類型而是其它類型,this自動設定為null,結果為全域物件。
第一個例子中,立即函數,它的函數呼叫小括號左邊是一個表達式,不是一個引用。
第二個例子複雜了許多,我們來個個分析:
foo.bar(),這個沒有疑問,base為foo,this指向foo。
(foo.bar)(),這裡用到了一個小括號,它在這起到分組符作用,也就是它不會迫使引用型別執行GetValue方法,其執行結果,跟上面一模一樣。
後面三個,小括號裡面依序是賦值運算、或運算和逗號運算,它們都會迫使引用型別執行GetValue方法,從而傳回一個函數物件。這樣,函數呼叫小括號左邊就不再是引用型別了,所有,this都是指向全域物件的。
總結
關於引用類型,其實我都一直不太了解這個,只是看到湯姆大叔的博客中this那章,為了解釋函數調用模式中this的取值原理且專門分析了一下,這一分析可不得了,我之前一直認為引用類型和引用傳值應該存在某些關係,沒想到,它大叔bolg中只是用來輔助理解this。至於他們二者之前有沒有關係,如果有關係到底是什麼關係,這還得我繼續學習研究。
希望大家多交流。在此還是的感謝湯姆大叔.