
Constructor
JS里沒有class,也就沒有class里的構(gòu)造函數(shù),那么object是怎么被創(chuàng)建的呢?用構(gòu)造器:constructor。constructor其實(shí)就是Function,因此本身也是object。開頭的function Base(){}就是一個(gè)構(gòu)造器,var b = new Base()就是用這個(gè)構(gòu)造器(通過關(guān)鍵字new)創(chuàng)建了一個(gè)叫b的object。至此我們可以得出結(jié)論,開頭的兩行代碼至少創(chuàng)建了2個(gè)object:一個(gè)是Base,類型為function的object,一個(gè)是base,類型為object的object。
Function()和Object()
這是兩個(gè)重要的預(yù)定義好的構(gòu)造器。一切function(比如開頭的Base())都是由Function()構(gòu)造出來的;而Object的prototype將會(huì)被所有object繼承,下面會(huì)講到。

Function的創(chuàng)建過程
當(dāng)執(zhí)行function Base(){this.a = 1}時(shí),相當(dāng)于var Base = new Function(“this.a = 1”),也就是說,這行代碼本身,將使用預(yù)定義好的Function() constructor,來構(gòu)造一個(gè)function型object(即Base)出來。在這個(gè)創(chuàng)建過程中,js將做哪些事呢?
1, 首先當(dāng)然會(huì)創(chuàng)建一個(gè)object起來,Base指向這個(gè)object。typeof 這個(gè)object = “function”

2, 給Base附上__proto__屬性,讓它等于Function這個(gè)構(gòu)造器的prototype(也是預(yù)定義好的)。這是很重要的一步,也是規(guī)律性的一步。(規(guī)律:)在執(zhí)行任意類似varx = new X()時(shí),都會(huì)把X的prototype賦給x的__proto__,也就是說,x.__proto__和X.prototype此時(shí)會(huì)指向同一個(gè)對象。

3, 為Base創(chuàng)建call屬性,該屬性是個(gè)function。因此我們可以這樣寫:Base.Call()

4, 為Base創(chuàng)建Construct屬性,該屬性也是個(gè)function。在執(zhí)行var base = new Base()時(shí),即會(huì)調(diào)用這個(gè)Construct屬性。
5, 為Base創(chuàng)建Scope,Length等屬性,略。
6, 為Base創(chuàng)建prototype屬性:先用new Object()創(chuàng)建一個(gè)對象,為這個(gè)對象創(chuàng)建一個(gè)屬性叫constructor,該屬性值設(shè)置為Base。再把Base的prototype設(shè)置為這個(gè)新創(chuàng)建的對象。偽代碼如下:
var x = new Object();
x.constructor = Base;
Base.prototype = x;
先把關(guān)注點(diǎn)放到2和6。
__proto__和prototype
從2可以看出來,任意一個(gè)用構(gòu)造器構(gòu)造出來的object(包括Objects和Functions),都會(huì)有__proto__屬性,指向該構(gòu)造器的prototype屬性。注意__proto__是個(gè)私有屬性,在IE上是看不到的,我用的是chrome,可以看到。
從6可以看出,任意一個(gè)用new Function()構(gòu)造出來的functions,都會(huì)有prototype屬性,該屬性是用new Object()構(gòu)建出來的,初始公開屬性只有一個(gè)constructor。

原型鏈
再來分析下第6步的偽代碼,也就是為function創(chuàng)建prototype的這一步:
var x = new Object(); // 參見2中的規(guī)律,會(huì)有x.__proto__= Object.prototype。
x.constructor = Base;
Base.prototype = x;
此時(shí)我們用Base()構(gòu)造一個(gè)對象出來:
var base= new Base(); // 參見2中的規(guī)律,會(huì)有base.__proto__ = Base.prototype,也就是 = x。// 因此有base.__proto__.__proto__ = x.__proto__// 而x.__proto__ = Object.prototype(見上一個(gè)代碼片段)// 所以,base.__proto__.__proto__ = Object.prototype.
__proto__.__proto__,這就是傳說中JS對象的原型鏈!由于用Function()創(chuàng)建構(gòu)造器時(shí)的關(guān)鍵的第6步,保證了所有object的原型鏈的頂端,最終都指向了Object.prototype。

Property Lookup
而我們?nèi)绻x某個(gè)object的某個(gè)屬性,JS會(huì)怎么做呢?
比如有個(gè)object叫xxx,我們執(zhí)行alert(xxx.a),也就是讀取xxx的a屬性,那么JS首先會(huì)到xxx本身去找a屬性,如果沒找到,則到xxx.__proto__里去找a屬性,由此沿著原型鏈往上,找到即返回(沒找到,則返回undefined)。可以來看個(gè)例子:

上圖得知:base本身是沒有constructor屬性的,但是base.constructor確實(shí)能返回Base這個(gè)函數(shù),原因就在于base.__proto__有這個(gè)屬性。(base.__proto__是啥?就是Base.prototype,上面構(gòu)建Function的第6步的偽代碼里,為Base.prototype.constructor賦值為Base本身。)
Object作為“基類”
另外,由于任意object的原型鏈的頂端都是Object.prototype。所以,Object.prototype里定義的屬性,就會(huì)通過原型鏈,被所有的object繼承下來。這樣,預(yù)定義好的Object,就成了所有對象的“基類”。這就是原型鏈的繼承。

看上圖,Object.prototype已經(jīng)預(yù)定義好了一些屬性,我們再追加一條屬性叫propertyA,那么這個(gè)屬性和預(yù)定義屬性一樣,都可以從base上讀到。
原型繼承
已經(jīng)得知,
對于 var xxx =new Object(); 有xxx.__proto__= Object.prototype;
對于 var xxx =new Base(); 有xxx.__proto__.__proto__= Object.prototype;
看上去很像什么呢?從c#角度看,很像Base是Object的子類,也就是說,由Base()構(gòu)造出來的object,比由Object()構(gòu)造出來的object,在原型鏈上更低一個(gè)層級。這是通過把Base.prototype指向由Object()創(chuàng)建的對象來做到的。那么自然而然,如果我想定義一個(gè)繼承自Base的構(gòu)造器,只需把改構(gòu)造器的prototype指向一個(gè)Base()構(gòu)造出來的對象。
function Derived(){}
var base = new Base();
Derived.prototype = base;
var d = newDerived(); //很容易推算出:d.__proto__.__proto__.__proto__ = Object.prototype.
推算過程:d.__proto__指向Derived.prototype,也就是base;則__proto__.__proto__指向base.__proto__,也就是Base.prototype,也就是某個(gè)new object()創(chuàng)建出來的東東,假設(shè)是o;則__proto__.__proto__.__proto__指向o.__proto__,也就是Object.prototype。
回答開頭的問題,以及幾個(gè)新的問題
那兩行代碼至少創(chuàng)建了三個(gè)對象:Base、base、Base.prototype。順便說說,base是沒有prototype屬性的,只有function類型的object,在被構(gòu)建時(shí)才會(huì)被創(chuàng)建prototype屬性。

d.constructor會(huì)返回什么呢?
構(gòu)造器Base()和Derived()里都是空的,如果有代碼,將會(huì)怎么被執(zhí)行呢?
……
待續(xù)。見下篇
新聞熱點(diǎn)
疑難解答