2011-12-28 76 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