javascript 对象继承 - 子类和超类

javascript object inheritance - subclass and superclass

这两种方法有什么区别?

第一种方法

// Shape - superclass
function Shape() {
    this.x = 0;
    this.y = 0;
}

// superclass method
Shape.prototype.move = function(x, y) {
    this.x += x;
    this.y += y;
};

// Rectangle - subclass
function Rectangle() {
    Shape.call(this);
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

第二种方法

// Shape - superclass
function Shape() {
    this.x = 0;
    this.y = 0;
}

// superclass method
Shape.prototype.move = function(x, y) {
    this.x += x;
    this.y += y;
};

// Rectangle - subclass
function Rectangle() {
    Shape.call(this);
}

// subclass extends superclass
Rectangle.prototype = new Shape();

var rect = new Rectangle();

最大的实际区别是,当您使用 new 时,将调用超级 class 的构造函数,而不需要 Shape.call(this);

主要区别在于,在第二种方法中,Shape 构造函数仅被调用一次。在第一种方法中,不调用 Shape 构造函数,而是 Object.create(Shape.prototype) 从原型创建一个新对象。然后可以使用 Shape.call.

为每个子构造调用一次父构造函数

您仍然可以像第二种方法一样为每个子类调用 Shape.call,但它会导致在初始原型创建期间额外调用构造函数。

此外,使用第一种方法 Object.create 会导致 constructor 属性 的 prototype 被覆盖,因此 Rectangle.prototype.constructor = Rectangle; 用于重置constructor 属性.

第二种方法的主要缺点是它需要额外调用一次 Shape 构造函数才能创建一个对象用作 Rectangle 的原型。有不同的方法来避免它,例如使用中间空函数:

function Rectangle() {
    Shape.call(this);
}

function f() {}
f.prototype = Shape.prototype;

Rectangle.prototype = new f();

如您所见,这显然很笨拙。

出于这个原因,使用 Object.create 的模式 #1 更方便、更高效。

但是请注意,这两个片段都有另一个问题:自己的属性是用 Shape.call(this); 复制的,这又是不受欢迎的。

Object.create 不执行构造函数。

用 New 调用相当于 Object.create(object.prototype) + 运行 构造函数。

我看到了两个区别:一大一小。

细微差别在于,在第二种方法中,Rectangle 原型不会正确设置 constructor 属性。它将指向 Shape,而不是 Rectangle。这是 JavaScript OO 方法中的一个极其常见的错误,大多数时候你可以摆脱它,因为人们不经常使用 constructor 属性,但它就在那里.

最大的不同是在第二个构造函数中额外调用了Shape()。在您的特定示例中,事情或多或少地解决了问题:Rectangle.prototype 有一些您可能不想要的额外属性(xy,两者都为零)有,但无论如何这些都会被 Rectangle 实例中的相应属性所掩盖。同样,这种非常常见但很小的错误经常发生,您可以摆脱它。

第二种方法的问题在于,它仅在超类构造函数不需要任何参数时才有效。您的示例恰好符合该描述,因为它所做的只是将某些属性初始化为默认值。但是存在这种设置不太合适的用例,在这些情况下不能使用第二种方法。