javascript对象继承 - 子类和超类

时间:2015-02-20 18:58:02

标签: javascript oop

这两种方法的区别是什么?

第一种方法

// 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();

5 个答案:

答案 0 :(得分:2)

我看到两个不同:一个大,一个小。

不同之处在于,在第二种方法中,Rectangle原型不会正确设置constructor属性。它将指向Shape,而不是Rectangle。这在JavaScript OO方法中是一个非常常见的错误,并且大多数情况下你可以逃脱它,因为人们不会非常使用constructor属性,但它就在那里。

最大的区别是第二个构造函数中对Shape()的额外调用。在您的特定示例中,事情或多或少都可以正常运行:Rectangle.prototype有一些额外的属性(xy,两者都等于零),您可能不打算这样做但是,无论如何,这些都会被Rectangle实例中的相应属性所掩盖。再一次,这种非常常见但很小的bug经常足以让你逃脱它。

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

答案 1 :(得分:1)

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

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

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

答案 2 :(得分:1)

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

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

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

Rectangle.prototype = new f();

如你所见,这显然非常笨拙。

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

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

答案 3 :(得分:0)

Object.create不执行构造函数。

使用New调用等效于Object.create(object.prototype)+运行构造函数。

答案 4 :(得分:-1)

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