2011-07-30 26 views
10

有人可以向我解釋使用Me.prototype.constructor = Me;以及爲什麼需要此代碼時,此代碼正常工作,沒有它?在JS中使用原型構造函數

在代碼中,原型對象是在Me對象上創建的,並且它被實例化並替換了舊的原型對象。爲什麼我需要在給定的代碼中指向Me構造函數?

function Me(){ 
    this.name = 'Dejan'; 

} 

function You(){ 
    this.name = 'Ivan'; 
} 

Me.prototype = new You(); 

somebody = new Me(); 

Me.prototype.constructor = Me; // Why? 

Me.prototype.foo = function(){ 
    alert('Proto Me!'); // It always fire up this alert, ether constructor is pointing to Me or not... ! 
} 

You.prototype.foo = function(){ 
    alert('Proto You!'); 
} 

somebody.foo(); 
alert(somebody.name); // Alert 'Dejan' 
+0

我相信舊式瀏覽器會檢查'instanceof'關鍵字的'.constructor'屬性。 – Raynos

+0

這是一本2006年以來的書。 –

回答

11

這不是必要的,它甚至沒有需要instanceof出乎人們意料的(內部的instanceof檢查原型鏈,而不是需要一個constructor屬性)。通常,constructor本質上是構造函數的prototype上的非可枚舉屬性。因此,給這個構造函數實例化的任何對象,一個不可枚舉的constructor屬性,指向該構造函數。

如果您需要,最好放在那裏,理想情況下不可枚舉。某些代碼將假定對象上存在.constructor。在你發佈的代碼中,是的,當以這種方式進行繼承時,需要重置構造函數(如果你需要它),因爲你實例化的作爲子原型的對象具有指向錯誤的構造函數屬性構造函數(它的構造函數)。

在ES5,你會怎麼做:

Child.prototype = Object.create(Parent.prototype, { 
    constructor: { value: Child, enumerable: false } 
}); 

編輯:另外,可能是值得一提的,使用非標準__proto__做繼承時,沒有必要重新構造,因爲__proto__僅僅規定和對象的原型,也就是說,當自己的屬性不存在時,將在其上執行查找的對象。新的prototype將始終有一個名爲constructor的屬性。

這樣做:

var child = function() {}; 
child.prototype.__proto__ = parent.prototype; 

您不必設置構造,因爲child.prototype的基本構造屬性仍然存在。如果被訪問,則不需要執行原型鏈查找。

+2

你確定IE6不檢查'constructor'屬性嗎?而'Object.create'爲你設置'constructor'屬性。你不必手動做 – Raynos

+4

Raynos,不,我不確定IE6,因爲我並不在意IE6。另外,Object.create沒有爲你設置構造函數,它沒有構造函數的概念,事實上,這就是Object.create的要點。你只會得到一個等於父構造函數的構造函數屬性,這對於繼承是錯誤的。所以你需要改變它。 – chjj

+1

你的權利我對'構造函數'不好​​。 Object.create沒有構造函數的概念 – Raynos

5

如果更換線

Me.prototype.constructor = Me; // Why? 

console.log(Me.prototype.constructor); 
Me.prototype.constructor = Me; // Why? 

你會發現,在設置前,Me.prototype.constructorYou,因爲Me.prototypeYou的情況下,由於線

Me.prototype = new You(); 

所以,與th e // Why?註釋有必要「修復」這種錯誤的印象,即您以這種方式繼承了JavaScript。


基本上問題出現了,因爲您試圖使用原型繼承來實現經典繼承。原型繼承適用於對象實例,並沒有「類」的概念,甚至沒有「類型」的概念,但JavaScript使整個業務的整個new,.constructorinstanceof業務變得更加混亂。

做這種事情的更原型的方法是避開構造有利於電源的構造,即功能與形式返回一個對象,你的願望:

function begetPart(partNumber, description) { 
    return Object.create({}, { 
     number: { value: partNumber }, 
     description: { value: description }, 
     describe: { 
      value: function() { 
       alert(this.description); 
      } 
     } 
    }); 
} 

function begetTire(partNumber, speed) { 
    return Object.create(
     begetPart(partNumber, "A tire"), 
     { 
      speed: { value: speed }, 
      describe: { 
       value: function() { 
        alert(this.description + "; speed = " + this.speed); 
       } 
      } 
     } 
    ); 
} 

var genericPart = begetPart(1234, "A widget"); 
genericPart.describe(); // alerts "A widget" 

var tire = begetTire(4567, "fast"); 
tire.describe(); // alerts "A tire; speed = fast" 

這裏我們使用Object.create說「基於這個其他對象實例創建一個對象實例「。另一個實例是一個新的空對象begetPart和一個新的「零件實例」,其中一些屬性預先填充爲begetTire

這更好地反映了JavaScript和原型繼承的實際工作原理,因爲原型繼承對象實例從其他對象實例繼承,沒有整個「類型」或「類」的想法阻礙。

+0

'function Object(){[native code]}' – towry

相關問題