Javascript淺談之引用類型
簡介
1.引用類型(Reference type)
引用類型是javascript中一種內(nèi)部類型。它主要是當(dāng)做一個指代,代替一個變量或者函數(shù),當(dāng)然在需要真實值時,又可以通過它尋找到真實值。
2.引用類型的結(jié)構(gòu)
引用類型的值時由兩部分構(gòu)成,一是引用類型的值指代的對象的所屬對象,這里我們姑且把它叫做base,二是base中的指代對象的對象名稱。用偽代碼來表示:
var valueOfReferenceType = {
base: <base object>,
propertyName: <property name>
};
3.使用情景
引用類型的使用情景有二:
(1)在處理一個標(biāo)示符時
標(biāo)示符是變量名,函數(shù)名,函數(shù)參數(shù)名和全局對象中未識別的屬性名。
(2)在處理一個屬性訪問器時
var foo = 10;
function bar( ){}
在操作的中間結(jié)果中,引用類型對應(yīng)
var fooReference = {
base: global,
propertyName: 'foo'
};
var barReference = {
base: global,
propertyName: 'bar'
};
這里還是有必要解釋一下base,在javascript中所有對象或者函數(shù)都有所屬對象,看過我前面文章的人都知道,在每個執(zhí)行上下文有個變量對象專門來管理這個執(zhí)行上下文中的變量或者函數(shù)。
所以,當(dāng)處理標(biāo)示符時:
在全局上下文中,毋庸置疑,base === globalVO === gloabal
在函數(shù)的執(zhí)行上下文中,base === VO/AO
但處理對象屬性是:
這個更是簡單,base === owerObject
4.獲取引用類型的真正值
一開始我們說了,引用類型只是一個指代,而不是它并不保存真正的值。當(dāng)需要真正的值時,可以通過內(nèi)部一系列算法,可以得到。這個算法,我們可以用簡單的偽代碼來描述:
function GetValue(value) {
if (Type(value) != Reference) {
return value;
}
var base = GetBase(value);
if (base === null) {
throw new ReferenceError;
}
return base.[[Get]](GetPropertyName(value));
}
內(nèi)部的[[Get]]方法返回對象屬性真正的值,包括對原型鏈中繼承的屬性分析。所有通過GetValue我們也可以輕松獲取引用類型的真正的值。如下例:
GetValue(fooReference); // 10
GetValue(barReference); // function object "bar"
那我們什么時候需要獲取引用類型的真正值呢?
一般是在引用類型需要進(jìn)行賦值、參與運算或者被調(diào)用是需要通過GetValue方法獲取真正值。(注意:通過GetValue獲取到的對象不再是引用類型)
引用類型與this的關(guān)系
引用類型主要是跟函數(shù)上下文中的this指向關(guān)系密切,且不同時候看起來還差異挺大,所有我們才引出引用類型來專門解釋函數(shù)上下文中this的表現(xiàn)。
函數(shù)上下文中確定this值的通用規(guī)則如下:
在一個函數(shù)上下文中,this由調(diào)用者提供,由調(diào)用函數(shù)的方式來決定。如果調(diào)用括號()的左邊是引用類型的值,this將設(shè)為引用類型值的base對象(base object),在其他情況下(與引用類型不同的任何其它屬性),這個值為null。不過,實際不存在this的值為null的情況,因為當(dāng)this的值為null的時候,其值會被隱式轉(zhuǎn)換為全局對象。注:第5版的ECMAScript中,已經(jīng)不強(qiáng)迫轉(zhuǎn)換成全局變量了,而是賦值為undefined。
下面我們根據(jù)調(diào)用括號左邊不同分三種情況進(jìn)行討論:
(1)調(diào)用括號左邊是引用類型的值
這無需作過多分析,base對象就是this值,找到base即可。如果是全局變量下申明的,那就指向全局對象。
var myObject = {
foo : function(){
console.log(this);
}
}
myObject.foo(); //毫無疑問,這個foo的base是myObject,故foo方法中的this指向myObject。
(2)調(diào)用括號左邊是引用類型的值,不過這個值為null
function myFunction() {
var foo = function(){
console.log(this);
}
foo(); //AO.foo() => null.foo()
}
myFunction(); //輸出:Window {top: Window, window: Window...}
當(dāng)一個內(nèi)部函數(shù)被調(diào)用時,這個內(nèi)部函數(shù)的base應(yīng)該是當(dāng)前執(zhí)行上下文中活動對象(OA),但是在javascript內(nèi)部在OA作為base時,都當(dāng)做null處理,javascript當(dāng)然不允許this為null的情況發(fā)生,所有就將base設(shè)置為global對象(這是前文this函數(shù)調(diào)用模式中設(shè)計錯誤的源頭)。所以在這情況下,this都指向全局對象。
(3)調(diào)用括號左邊不是引用類型的值
//簡單點的例子
(function () {
console.log(this); // null => global
})();
//復(fù)雜些的例子
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
當(dāng)調(diào)用括號的左邊不是引用類型而是其它類型,this自動設(shè)置為null,結(jié)果為全局對象。
第一個例子中,立即函數(shù),它的函數(shù)調(diào)用小括號左邊是一個表達(dá)式,不是一個引用。
第二個例子復(fù)雜了許多,我們來一個個分析:
foo.bar(),這個沒有疑問,base為foo,this指向foo。
(foo.bar)(),這里用到了一個小括號,它在這起到分組符作用,也就是它不會迫使引用類型執(zhí)行GetValue方法,其執(zhí)行結(jié)果,跟上面一模一樣。
后面三個,小括號里面依次是賦值運算、或運算和逗號運算,它們都會迫使引用類型執(zhí)行GetValue方法,從而返回一個函數(shù)對象。這樣,函數(shù)調(diào)用小括號左邊就不再是引用類型了,所有,this都是指向全局對象的。
總結(jié)
關(guān)于引用類型,其實我都一直不太了解這個,只是看到湯姆大叔的博客中this那章,為了解釋函數(shù)調(diào)用模式中this的取值原理且專門分析了一下,這一分析可不得了,我之前一直認(rèn)為引用類型和引用傳值應(yīng)該存在某些關(guān)系,沒想到,它大叔bolg中只是用來輔助理解this。至于他們二者之前有沒有關(guān)系,如果有關(guān)系到底是一種什么關(guān)系,這還得我繼續(xù)學(xué)習(xí)研究。
希望大家多交流。在此還是的感謝湯姆大叔.
- JavaScript中值類型與引用類型實例說明
- 《JavaScript高級程序設(shè)計》閱讀筆記(三) ECMAScript中的引用類型
- JavaScript之引用類型介紹
- JavaScript中“基本類型”之爭小結(jié)
- Javascript delete 引用類型對象
- 淺析JavaScript基本類型與引用類型
- javascript基本類型詳解
- JavaScript數(shù)據(jù)類型之基本類型和引用類型的值
- javascript引用類型指針的工作方式
- javascript中基本類型和引用類型的區(qū)別分析
- javascript引用類型之時間Date和數(shù)組Array
- 《JavaScript高級編程》學(xué)習(xí)筆記之object和array引用類型
- 跟我學(xué)習(xí)javascript的基本類型和引用類型
基于JavaScript實現(xiàn)繼承機(jī)制之調(diào)用call()與apply()的方法詳解
ECMAScript 5嚴(yán)格模式(Strict Mode)介紹
怎樣在JavaScript里寫一個swing把數(shù)據(jù)插入數(shù)據(jù)庫

