再談JavaScript中對象的prototype鏈
ECMAScirpt可以識別兩種類型的對象:
1.Navtive Object 指語言級別的對象
2.Host Object 有運行環境提供如:document
Native objects是一種鬆散的結構並且可以動態的增加屬性(property),所有的屬性都有一個名字和一個值,這個值可以是另一個對象的引用,或者內建的數據類型(String ,Number,Boolean,Null,Undefined).
下麵我們通過一個簡單的例子,來看看一個JavaScript是如何設置一個屬性的值和讀取一個屬性的值。
var objectRef = new Object();//create a generic javascript object
下麵來為該對象添加屬性:
objectRef.testNumber = 5; /* - or:- */ objectRef["testNumber"] = 5;
一個名為testNumber的屬性就這樣被創建。
如果賦值的屬性的名稱已經存在,那麼就不會再次創建這個屬性,賦值操作僅僅是重新設置屬性的值objectRef.testNumber = 8; /* - or:- */ objectRef["testNumber"] = 8;
JavaScript對象的原型(prototype)本身也是對象,也可以有屬性(property),對於JavaScript對象的prototype的賦值操作更普通的對象沒有什麼不同,那麼對於取值操作來說就不同了,下麵我們具體來看取值操作:
取值操作
在取值操作中prototype和property就不一樣了,首先來看最簡單的取值操作.
/*為一個對象的屬性賦值,如果這個對象沒有這個屬性,那麼在賦值操作後,這個對象就有這個屬性了 */ objectRef.testNumber = 8; /* 讀出這個屬性的值 */ var val = objectRef.testNumber; /* 現在val 就得到了剛才賦予objectRef的值8了*/
prototype揭密
我們首先整明白這幾句話
- 所有的對象都可以有prototypes。
- prototypes自己也是對象,那麼他也可以有prototypes,這樣循環下去就形成了一個prototype鏈。
- 這個鏈當他遇到鏈中隊形的prototype是null時中止。(Object的默認的prototype是null)
下麵具體來看代碼:
var objectRef = new Object(); //create a generic javascript object.
創建一個新的JavaScript對象,這時這個對象的prototype是Null,所以objectRef的prototype鏈隻包含一個對象Object.prototype。
繼續看代碼:
/* 構建MyObject1這個類型的構造函數 MyObject1 - type. */ function MyObject1(formalParameter){ /* 為者對象創建一個屬性名字叫testNumber */ this.testNumber = formalParameter; } /* 構建MyObject2這個類型的構造函數 MyObject2 - type:- */ function MyObject2(formalParameter){ /* 為者對象創建一個屬性名字叫testString*/ this.testString = formalParameter; } /* 下一步的操作會用MyObject1對象替換掉MyObject2默認的prototype屬性*/ MyObject2.prototype = new MyObject1( 8 ); /* 最後我們創建MyObject2類型的一個對象*/ var objectRef = new MyObject2( "String_Value" );
下麵來解釋這段代碼:
- objectRef這個MyObject2類型的對象有一個prototype的鏈,鏈中的第一個對象是MyObject1對象。
- MyObject1對象也有prototype,這個prototype是Object默認的prototype。
- Object.prototype的prototype是null,至此這條prototype鏈結束。
因此當一個取值操作發生時,objectRef 的整個prototype鏈就開始工作
var val = objectRef.testString;
objectRef這個對象的有一個屬性叫做testString,那麼上麵這句代碼會把testString的值賦給val
var val = objectRef.testNumber;
在objectRef這個對象裏並沒有testNumber這個屬性,但是val卻的到了值8,而不是undefine,這是因為解釋器在沒有在當前對象找到要找
的屬性後,就會去檢查這個對象的prototype,objectRef的prototype是MyObject1對象,這個對象有testNumber這個屬性,所以val得到8這個值。
var val = objectRef.toString;
現在val是個function的引用,這個function是Object.prototype的property,由於MyObject1和MyObject2都沒有定義toString這個property
所以Object.prototype返回
var val = objectRef.madeUpProperty;
最後val是undefined,因為MyObject1和MyObject2,還有Object都沒有定義madeUpProperty這個property,所以得到的是undefine.
讀操作會讀取在obj自己和prototype 鏈上發現的第一個同名屬性值。
寫操作會為obj對象本身創建一個同名屬性(如果這個屬性名不存在
這就意味著objectRef.testNumber = 3會在objectRef對象上創建一個property,名字是testNumber,當下一次在要讀取testNumber時
propertype鏈就不會工作,僅僅會得到objectRef的property 3,而MyObject1的testNumber屬性並不會被修改).
由下麵的代碼為證:
/* 構建MyObject1這個類型的構造函數 MyObject1 - type. */ function MyObject1(formalParameter){ /* 為者對象創建一個屬性名字叫testNumber */ this.testNumber = formalParameter; } /* 構建MyObject2這個類型的構造函數 MyObject2 - type:- */ function MyObject2(formalParameter){ /* 為者對象創建一個屬性名字叫testString*/ this.testString = formalParameter; } /* 下一步的操作會用MyObject1對象替換掉MyObject2默認的prototype屬性*/ var obj1 = new MyObject1( 8 ); MyObject2.prototype = obj1; /* 最後我們創建MyObject2類型的一個對象*/ var objectRef = new MyObject2( "String_Value" ); alert(objectRef.testNumber); objectRef.testNumber = 5; alert(objectRef.testNumber); alert(obj1.testNumber);
最後更新:2017-04-02 00:06:41