我最近在学习javascript中基于原型的面向对象编程。在阅读了大量用javascript解释原型机制的网站后,我决定使用Mozilla的这种方法
以下是Mozilla的一些代码片段:
// Shape - superclass
function Shape() {
this.x = 0;
this.y = 0;
}
// superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info("Shape moved.");
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;
var rect = new Rectangle();
rect instanceof Rectangle // true.
rect instanceof Shape // true.
rect.move(1, 1); // Outputs, "Shape moved."我知道Rectangle.prototype = Object.create(Shape.prototype);会正确地设置原型链,这样Rectangle的实例就会继承Shape的方法。
但是Rectangle.prototype.constructor = Rectangle;这一行有点让人迷惑。
从this website我知道,当我们创建像function MyClass(){}这样的新对象时,javascript会将其原型设置为空对象,并且MyClass.prototype.constructor将指向MyClass。因此Rectangle.prototype.constructor = Rectangle;将修复断开的链接,因为Object.create(Shape.prototype).constructor仍然指向Shape。
但是如果我删除这一行,我仍然可以运行下面的代码而不会出现问题。我只是好奇是否有任何构造函数属性的用例?如果我只是让它指向超类,会出什么问题?
发布于 2014-01-17 12:41:13
以这种方式设置属性将使其成为可枚举的( for in语句将列出构造函数属性)。
var rec = new Rectangle();
'constructor' in rec; //true您应该使用Object.defineProperty或将第二个参数传递给Object.create。
Rectangle.prototype = Object.create(Shape.prototype, {constructor: {enumerable: false }});
var rec = new Rectangle();
'constructor' in rec; //有关构造函数属性的更多信息,请参阅此线程:
发布于 2014-01-17 14:00:27
在您的代码中,这没有任何区别,因为您仍然使用Rectangle构造函数(显式地使用其名称:var rect = new Rectangle();)创建对象。
唯一的区别是,当你丢失了对object构造函数的引用,或者你根本不知道它是什么:
// Shape - superclass
function Shape() {
this.x = 1;
this.y = 1;
}
// superclass method
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
console.info(this.x + " " + this.y);
};
// Rectangle - subclass
function Rectangle() {
Shape.call(this); // call super constructor.
}
// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
//Rectangle.prototype.constructor = Rectangle;
console.info("RECT");
var rect = new Rectangle;
console.info(rect);
console.info(rect instanceof Rectangle);
console.info(rect instanceof Shape);
//console.info(rect instanceof Square); TypeError - Square must be a function, but is still not initialized
rect.move(1, 1);
console.info("RECT2");
var rect2 = new rect.constructor();
console.info(rect2);
console.info(rect2 instanceof Rectangle);
console.info(rect2 instanceof Shape);
// console.info(rect2 instanceof Square); TypeError - Square must be a function, but is still not initialized
rect2.move(1, 1);
console.info("RECT3");
var Square = rect.constructor;
Square.prototype.move = function(x, y) { // just to make it different
this.x *= x;
this.y *= y;
console.info(this.x + " " + this.y);
}
var rect3 = new Square();
console.info(rect3);
console.info(rect3 instanceof Rectangle);
console.info(rect3 instanceof Shape);
console.info(rect3 instanceof Square);
rect3.move(4, 4);我在设置构造函数时注释掉了这一行。取消注释以查看输出中的差异。我还添加了另一种使用构造函数属性的方法--另一个继承示例(基于Shape的Square,但具有不同的move方法)。
因此,如果您不修复这个链接,在我展示的例子中,您将使用Shape构造函数,并且创建相同类型的对象将变得不可能。rect是这两种类型的,但rect2不再是。
因此,假设即使您不需要它,将此链接修复到正确的构造函数也是一个非常好的实践,因为将来使用您的代码的人可能需要它。
编辑:
constructor属性不会影响object本身的任何内容。它是在创建object后设置的,用于将reference保存到创建object的function中。如果你将来需要它,那么有一个正确的版本是有意义的。我看不到任何其他问题。
发布于 2014-01-17 14:00:05
如果对象在其继承链中属于指定的对象类型,则instanceOf将返回true。它与构造函数属性无关。
如果我们想在创建对象时初始化属性或执行默认代码,我们可以使用构造函数属性。
例如,在您的示例中,如果我们想要创建始终为红色的矩形,可以使用Rectangle的构造函数,如下所示:
function Rectangle() {
Shape.call(this); // call super constructor.
this.color = "red";
}希望这能清除你的疑问。
https://stackoverflow.com/questions/21177995
复制相似问题