一、對象從何而來
首先來看什麼是對象,搜尋wiki百科可以得到解釋,在物件導向(Object Oriented) 的軟體中,對象(Object)是某一個類(Class)的執行個體(Instance) ,因此說有對象之前必須先有類型,然後再將類型執行個體化就得到了對象。
那麼在JavaScript中,類型不是通過如java的聲明的方式定義,而是通過function的方式獲得的,如
1: function DemoClass(){}
2:
3: var x = new DemoClass();
注意:這個順序不能改變,必須先有function才能獲得對象,否則會出現指令碼錯誤,這是因為JavaScript的解析器是按順序解析的,如果使用了還未被解析的function就會出現錯誤,由於這類function用來構造對象,把這類function叫做構造器
二、構造器的結構
每個構造器都有prototype屬性,這個屬性的結構是字典,可以任意添加名-值對組合,如
1: function DemoClass(){}
2:
3: DemoClass.prototype.Name = "DemoClass";
4:
5: DemoClass.prototype.IsNum = function(){return ture;};
同時每個構造器的prototype屬性都有一個constructor屬性指向構造器自身,構造器的prototype的類型為Object
三、對象的結構
每個對象都有__proto__唯讀屬性,這個屬性指向構造器的prototype屬性。
除此之外,對象還有一個隱藏的內部屬性,這個屬性結構也是字典,可以任意添加名-值對組合
因此修改了構造器的prototype字典,所有由該構造器產生的對象的屬性就會發生改變,如果只是對一個對象執行個體修改了屬性,其他對象執行個體不會受到影響,如
1: function DemoClass(){}
2: DemoClass.prototype.Name = "DemoClass";
3: DemoClass.prototype.IsNum = function(){return ture;};
4: var x = new DemoClass();
5: var y = new DemoClass();
6: DemoClass.prototype.Name = "DemoClass1"; /* x.Name == y.Name */
7: x.Name = "DemoClass2"; /* x.Name != y.Name */
四、對象屬性的讀取和修改
由於每個對象實際上都會有兩個字典,因此必然要有先後順序,而且讀取和修改的策略也不同
讀取時,首先從對象自身的字典中讀取,若找到則返回,未找到時再從__proto__指向的字典中尋找,若找到則返回,若未找到則返回undefined。
修改時,直接向對象自身的字典中添加或修改,不對__proto__指向的字典操作
這樣的策略保證了對單個對象屬性的修改不會影響到其他對象,同樣的對象在不同的運行時環境裡就有了不同的行為即“動態性”。
五、再看構造器
看如下代碼
1: function DemoClass(){}
2: DemoClass.prototype.Name = "DemoClass";
3: function DemoClass1(){}
4: DemoClass1.prototype.Name = "DemoClass1";
5: var x = new DemoClass();
6: var y = new DemoClass1();
聲明兩個構造器並且給每個構造器都執行個體化了對象,通過測試發現,兩個構造器的prototype所指的字典並不相同,但是類型都為object
從這些可以看出,構造器被調用時,其prototype屬性是一個object的執行個體,下面是用C來描述構造器和對象的結構
1: //構造器
2: struct Constructure{
3: object prototype;
4: Constructure(){
5: this.prototype = new object();
6: this.prototype.constructor = this;
7: }
8: }
9: //對象
10: struct Instance{
11: Constructure* __proto__;
12: object innerdict;//內部的字典
13: Instance(){
14: this.innerdict = new object();
15: this.__proto__ = JSRuntime["Constructure"];//通過運行時擷取構造器地址
16: }
17: }