標籤:spi bsp concepts 運行機制 top null 一點 原型 task
附上原文出處:http://hzjavaeyer.group.iteye.com/group/wiki/3086-JavaScript-core-concepts
一、概念:
原型對象:JavaScript對象是一個屬性的集合,另外有一個隱式的對象:原型對象。原型的值可以是一個對象或者null。一般的引擎實現中,JS對象會包含若干個隱藏屬性,對象的原型由這些隱藏屬性之一引用,我們在本文中討論時,將假定這個屬性的名稱為"__proto__"(事實上,SpiderMonkey內部正是使用了這個名稱,但是規範中並未做要求,因此這個名稱依賴於實現)。
原型鏈:由於原型對象本身也是對象,根據上邊的定義,它也有自己的原型,而它自己的原型對象又可以有自己的原型,這樣就組成了一條鏈,這個就是原型鏈,JavaScritp引擎在訪問對象的屬性時,如果在對象本身中沒有找到,則會去原型鏈中尋找,如果找到,直接傳回值,如果整個鏈都遍曆且沒有找到屬性,則返回undefined.原型鏈一般實現為一個鏈表,這樣就可以按照一定的順序來尋找。
二、執行個體:
No1:
1 var base = { 2 name : "base", 3 getInfo : function(){ 4 return this.name; 5 } 6 } 7 8 var ext1 = { 9 id : 0,10 __proto__ : base11 }12 13 var ext2 = {14 id : 9,15 __proto__ : base16 }17 18 print(ext1.id);19 print(ext1.getInfo());20 print(ext2.id);21 print(ext2.getInfo());
結果為:
0
base
9
base
圖1:上例中對象的原型鏈
可以看到,當執行ext1.id時,引擎在ext1對象本身中就找到了id屬性,因此返回其值0,當執行ext1.getInfo時,ext1對象中沒有找到,因此在其原型對象base中尋找,找到之後,執行這個函數,得到輸出”base”。
我們將上例中的ext1對象稍加修改,為ext1對象加上name屬性:
NO2:
1 var base = { 2 name : "base", 3 getInfo : function(){ 4 return this.name; 5 } 6 } 7 8 var ext1 = { 9 id : 0,10 name : "ext1", 11 __proto__ : base12 }13 14 print(ext1.id);15 print(ext1.getInfo());
可以得到:
0
ext1
這個運行效果同樣驗證了原型鏈的運行機制:從對象本身出發,沿著__proto__尋找,直到找到屬性名稱相同的值(沒有找到,則返回undefined)。
我們對上例再做一點修改,來更好的示範原型鏈的工作方式:
NO3:
1 var base = { 2 name : "base", 3 getInfo : function(){ 4 return this.id + ":" + this.name; 5 } 6 } 7 8 var ext1 = { 9 id : 0,10 __proto__ : base11 }12 13 print(ext1.getInfo());
我們在getInfo函數中加入this.id,這個id在base對象中沒有定義。同時,刪掉了ext1對象中的name屬性,執行結果如下:
0:base
應該注意的是,getInfo函數中的this表示原始的對象,而並非原型對象。上例中的id屬性來自於ext1對象,而name來自於base對象。這個特性的機制在10.3小節再做討論。如果對象沒有顯式的聲明自己的”__proto__”屬性,這個值預設的設定為Object.prototype,而Object.prototype的”__proto__”屬性的值為”null”,標誌著原型鏈的終結。
三、構造器:
我們在來討論一下構造器,除了上邊提到的直接操作對象的__proto__屬性的指向以外,JavaScript還支援構造器形式的對象建立。構造器會自動的為新建立的對象設定原型對象,此時的原型對象通過構造器的prototype屬性來引用。
我們以例子來說明,將Task函數作為構造器,然後建立兩個執行個體task1, task2:
1 function Task(id){ 2 this.id = id; 3 } 4 5 Task.prototype.status = "STOPPED"; 6 Task.prototype.execute = function(args){ 7 return "execute task_"+this.id+"["+this.status+"]:"+args; 8 } 9 10 var task1 = new Task(1);11 var task2 = new Task(2);12 13 task1.status = "ACTIVE";14 task2.status = "STARTING";15 16 print(task1.execute("task1"));17 print(task2.execute("task2"));
結果:
execute task_1[ACTIVE]:task1
execute task_2[STARTING]:task2
構造器會自動為task1,task2兩個對象設定原型對象Task.prototype,這個對象被Task(在此最為構造器)的prototype屬性引用,參看中的箭頭指向。
圖2:構造器方式的原型鏈
由於Task本身仍舊是函數,因此其”__proto__”屬性為Function.prototype, 而內建的函數原型對象的”__proto__”屬性則為Object.prototype對象。最後Obejct.prototype的”__proto__”值為null.
js原型和原型鏈[轉]