欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Javascript之旅 對(duì)象的原型鏈之由來

 更新時(shí)間:2010年08月25日 19:48:54   作者:  
本人是Javascript菜鳥,下面是前幾天學(xué)習(xí)Javascript的旅程心得,希望對(duì)和我一樣的入門者有點(diǎn)用,也希望高手批評(píng)指正。
以問題開始:

function Base(){}var base = new Base()
上面兩行代碼會(huì)創(chuàng)建幾個(gè)對(duì)象(object)?

要回答這個(gè)問題,先明確一下Javascript里object的概念。


Objects

在Javascript里,幾乎一切都是object(Arrays、Functions、Numbers、Objects……),而沒有C#里的class的概念。object的本質(zhì)是一個(gè)name-value pairs的集合,其中name是string類型的,可以把它叫做“property”,value包括各種objects(string,number,boolean,array,function…),指的是property的值。


typeof

既然object包含Arrays、Functions、Numbers、Objects……,那怎么區(qū)分這些呢?答案是typeof。 typeof返回一個(gè)字符串,如typeof(Null) = “object”,typeof(false) = “Boolean”, typeof(1) = “number”。既然總是返回字符串,那么對(duì)于typeof (typeof x),不管x是什么,總是返回”string”。


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è)對(duì)象。

     
  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è)對(duì)象,為這個(gè)對(duì)象創(chuàng)建一個(gè)屬性叫constructor,該屬性值設(shè)置為Base。再把Base的prototype設(shè)置為這個(gè)新創(chuàng)建的對(duì)象。偽代碼如下:

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è)對(duì)象出來:

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對(duì)象的原型鏈!由于用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,就成了所有對(duì)象的“基類”。這就是原型鏈的繼承。

    

看上圖,Object.prototype已經(jīng)預(yù)定義好了一些屬性,我們?cè)僮芳右粭l屬性叫propertyA,那么這個(gè)屬性和預(yù)定義屬性一樣,都可以從base上讀到。

 

原型繼承

已經(jīng)得知,

對(duì)于 var xxx =new Object(); 有xxx.__proto__= Object.prototype;

對(duì)于 var xxx =new Base(); 有xxx.__proto__.__proto__= Object.prototype;

看上去很像什么呢?從c#角度看,很像Base是Object的子類,也就是說,由Base()構(gòu)造出來的object,比由Object()構(gòu)造出來的object,在原型鏈上更低一個(gè)層級(jí)。這是通過把Base.prototype指向由Object()創(chuàng)建的對(duì)象來做到的。那么自然而然,如果我想定義一個(gè)繼承自Base的構(gòu)造器,只需把改構(gòu)造器的prototype指向一個(gè)Base()構(gòu)造出來的對(duì)象。

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è)對(duì)象: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ù)。見下篇

相關(guān)文章

最新評(píng)論