Javascript參考型別
這篇文章主要介紹了Javascript參考型別,有需要的朋友可以參考一下
簡介
1.參考型別(Reference type)
參考型別是javascript中一種內部類型。它主要是當做一個指代,代替一個變數或者函數,當然在需要真實值時,又可以通過它尋找到真實值。
2.參考型別的結構
參考型別的值時由兩部分構成,一是參考型別的值指代的對象的所屬對象,這裡我們姑且把它叫做base,二是base中的指代對象的對象名稱。用虛擬碼來表示:
代碼如下:
var valueOfReferenceType = {
base: <base object>,
propertyName: <property name>
};
3.使用情景
參考型別的使用情景有二:
(1)在處理一個標示符時
標示符是變數名,函數名,函數參數名和全域對象中未識別的屬性名稱。
(2)在處理一個屬性訪問器時
代碼如下:
var foo = 10;
function bar( ){}
在操作的中間結果中,參考型別對應
代碼如下:
var fooReference = {
base: global,
propertyName: 'foo'
};
var barReference = {
base: global,
propertyName: 'bar'
};
這裡還是有必要解釋一下base,在javascript中所有對象或者函數都有所屬對象,看過我前面文章的人都知道,在每個執行內容有個變數對象專門來管理這個執行內容中的變數或者函數。
所以,當處理標示符時:
在全域上下文中,毋庸置疑,base === globalVO === gloabal
在函數的執行內容中,base === VO/AO
但處理對象屬性是:
這個更是簡單,base === owerObject
4.擷取參考型別的真正值
一開始我們說了,參考型別只是一個指代,而不是它並不儲存真正的值。當需要真正的值時,可以通過內部一系列演算法,可以得到。這個演算法,我們可以用簡單的虛擬碼來描述:
代碼如下:
function GetValue(value) {
if (Type(value) != Reference) {
return value;
}
var base = GetBase(value);
if (base === null) {
throw new ReferenceError;
}
return base.[[Get]](GetPropertyName(value));
}
內部的[[Get]]方法返回對象屬性真正的值,包括對原型鏈中繼承的屬性分析。所有通過GetValue我們也可以輕鬆擷取參考型別的真正的值。如下例:
代碼如下:
GetValue(fooReference); // 10
GetValue(barReference); // function object "bar"
那我們什麼時候需要擷取參考型別的真正值呢?
一般是在參考型別需要進行賦值、參與運算或者被調用是需要通過GetValue方法擷取真正值。(注意:通過GetValue擷取到的對象不再是參考型別)
參考型別與this的關係
參考型別主要是跟函數上下文中的this指向關係密切,且不同時候看起來還差異挺大,所有我們才引出參考型別來專門解釋函數上下文中this的表現。
函數上下文中確定this值的通用規則如下:
在一個函數上下文中,this由調用者提供,由調用函數的方式來決定。如果調用括弧()的左邊是參考型別的值,this將設為參考型別值的base對象(base object),在其他情況下(與參考型別不同的任何其它屬性),這個值為null。不過,實際不存在this的值為null的情況,因為當this的值為null的時候,其值會被隱式轉換為全域對象。註:第5版的ECMAScript中,已經不強迫轉換成全域變數了,而是賦值為undefined。
下面我們根據調用括弧左邊不同分三種情況進行討論:
(1)調用括弧左邊是參考型別的值
這無需作過多分析,base對象就是this值,找到base即可。如果是全域變數下申明的,那就指向全域對象。
代碼如下:
var myObject = {
foo : function(){
console.log(this);
}
}
myObject.foo(); //毫無疑問,這個foo的base是myObject,故foo方法中的this指向myObject。
(2)調用括弧左邊是參考型別的值,不過這個值為null
代碼如下:
function myFunction() {
var foo = function(){
console.log(this);
}
foo(); //AO.foo() => null.foo()
}
myFunction(); //輸出:Window {top: Window, window: Window...}
當一個內建函式被調用時,這個內建函式的base應該是當前執行內容中使用中的物件(OA),但是在javascript內部在OA作為base時,都當做null處理,javascript當然不允許this為null的情況發生,所有就將base設定為global對象(這是前文this函數調用模式中設計錯誤的源頭)。所以在這情況下,this都指向全域對象。
(3)調用括弧左邊不是參考型別的值
複製代碼 代碼如下:
//簡單點的例子
(function () {
console.log(this); // null => global
})();
//複雜些的例子
var foo = {
bar: function () {
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。至於他們二者之前有沒有關係,如果有關係到底是一種什麼關係,這還得我繼續學習研究。
希望大家多交流。在此還是的感謝湯姆大叔.