2011-12-28 87 views
3

我正在學習JS原型。子類不能調用其父類的原型方法

Java語言點我期望,SpecificRectangle對象將有權訪問area()方法,由於area()是其父類(Rectangle類)原型的方法。

function Rectangle(w,h){ 
this.width = w; 
this.height=h; 
} 
Rectangle.prototype.area = function(){return this.width*this.height} 

function SpecificRectangle(w,h,angle){ 
    Rectangle.call(this,w,h); 
    SpecificRectangle.prototype=new Rectangle(); 
} 

var specrec = new SpecificRectangle(7,8,45); 

所有的一切我不能SpecificRectangle實例調用area()方法。
標準JS錯誤有:

TypeError: specrec.area is not a function 
[Break On This Error] specrec.area() 

什麼解釋,這種封裝的原因是什麼?

回答

3

老實說,我不知道確切的原因,但你需要設置原型的構造函數外:

function SpecificRectangle(w, h, angle) { 
    Rectangle.call(this,w,h); 
} 

SpecificRectangle.prototype = new Rectangle(); 
SpecificRectangle.prototype.constructor = SpecificRectangle; // Otherwise instances of SpecificRectangle would have a constructor of Rectangle 

工作實例here


編輯由@herby評論如下:

看來確實是,上方法可能會破壞原型繼承取決於超類的構造函數是如何構建的(見this article)。

更健壯的解決方案是使用Object.createsource - 感謝特此)

// in case Object.create does not exist 
if (typeof Object.create !== 'function') { 
    Object.create = function(o) { 
     var F = function() {}; 
     F.prototype = o; 
     return new F(); 
    }; 
} 

function Rectangle(w, h) { 
    this.width = w; 
    this.height = h; 
} 
Rectangle.prototype.area = function() { 
    return this.width * this.height 
} 

function SpecificRectangle(w, h, angle) { 
    Rectangle.call(this, w, h); 
} 

SpecificRectangle.prototype = Object.create(Rectangle.prototype); 
SpecificRectangle.prototype.constructor = SpecificRectangle; 

var r = new SpecificRectangle(100, 50, 30); 
alert(r.area()); 

更新例如在jsfiddle

+0

不錯,工作正常 – sergionni 2011-12-28 13:28:29

+0

你不應該使用'SpecificRectangle.prototype = new Rectangle()'。它工作很多次,但原則上是不正確的。如果你有ES5,你應該使用'SpecificRectangle.prototype = Object.create(Rectangle.prototype)'來代替,如果你不能保證ES5,你應該像'function create(proto){function f(){} f一樣定義create。原型=原型;返回新的f(); }'併發出'SpecificRectangle.prototype = create(Rectangle.prototype)'。問題是,原型不應該是超類的初始實例,它應該只是從原型繼承而不實際初始化。 – 2011-12-28 14:16:51

+0

感謝您的評論。這導致我閱讀這篇關於你所描述的問題的文章(http://www.bennadel.com/blog/2180-Your-Javascript-Constructor-Logic-May-Break-Prototypal-Inheritance.htm) [第](HTTP://www.bennadel。com/blog/2184-Object-create-Improves-Based-Inheritance-In-Javascript-It-Doesn-t-Replace-It.htm)在Object.create(閱讀註釋)。 – 2011-12-28 14:34:55

0

您應該複製基類原型。例如:

function Rectangle(w,h){ 
    this.width = w; 
    this.height=h; 
} 
Rectangle.prototype.area = function(){return this.width*this.height} 

function SpecificRectangle(w,h,angle){ 
    Rectangle.call(this,w,h); 
} 
function SpecificRectangleProto(){} 
SpecificRectangleProto.prototype = Rectangle.prototype; 
SpecificRectangle.prototype = new SpecificRectangleProto(); 

var specrec = new SpecificRectangle(7,8,45); 
alert(specrec.area); 

我建議從某個框架中提取擴展方法。例如ExtJS。 有了這樣的方法,你可以像這樣的擴展類:

SpecificRectangle = extend(Rectangle, { 
    constructor: function(w,h,angle){ 
     SpecificRectangle.superclass.constructor.call(this,w,h); 
    } 
}); 
+0

決不做:'SpecificRectangle.prototype = {}; (Rectangle.prototype中的var i){ SpecificRectangle.prototype [i] = Rectangle.prototype [i]; } '!你應該繼承,而不是混合在一起。 – 2011-12-28 14:13:17

+0

@herby第二想到我看到這個問題。如果原始原型發生更改,則更改不會傳播到子類。它可能不是經常使用,但可視化問題。 – Krzysztof 2011-12-28 14:54:09