Javascript继承 - 创建相同类型的实例

时间:2013-04-19 17:07:46

标签: javascript oop

说我有一个班级BaseClass和两个班级ClassAClassBBaseClass通过

继承
ClassA.prototype = Object.create( BaseClass.prototype );

我想编写一个方法,如果从ClassA的实例调用,则返回ClassA的新实例,如果从ClassB的实例调用,则返回一个新实例ClassB - 我想知道最好的方法是什么。 目前,在摆弄后,我想出了以下解决方案,这似乎工作正常:

// this is added additionally to the above mentioned inheritance setup
ClassA.prototype.constructor = ClassA;
ClassB.prototype.constructor = ClassB;

BaseClass.prototype.newInstance = function () {
    var constructor = this.constructor,
        ClassFactory = constructor.bind.apply( constructor, [constructor].concat( [].slice.call( arguments ) ) );

    return new ClassFactory();
};

明显的缺点是覆盖原型的构造函数,这感觉不对,因为原型的构造函数实际上 BaseClass

另一种应该有效的方法是重写方法:

BaseClass.prototype.newInstance = function () {
    throw new Error( 'Cannot call abstract method.' );
};

/** @override */
ClassA.prototype.newInstance = function () {
    var ClassFactory = ClassA.bind.apply( ClassA, [ClassA].concat( [].slice.call( arguments ) ) );

    return new ClassFactory();
};

// ... do the same for ClassB

现在我的问题是要求对哪种策略更好以及为什么,每种策略的上行和下行都有一些见解,甚至可能有更好的方法?

编辑:为了澄清目标是什么,我想最终做这样的事情:

BaseClass.prototype.someMethod = function () {
    var instance = this.getInstance();
    instance.someMethod();

    return instance;
};

现在,由于ClassAClassB将继承此方法,我希望它返回与其调用的同一个类的新实例。

1 个答案:

答案 0 :(得分:1)

ClassA.prototype.constructor = ClassA;
ClassB.prototype.constructor = ClassB;
     

明显的缺点是覆盖原型的构造函数,这感觉不对,因为原型的构造函数实际上是BaseClass。

不,原型对象不是由BaseClass构建的。您只需Object.create d他们,甚至BaseClass.prototype创建为普通Object

将对象[back]上的constructor属性设置为构造从该对象继承的实例的函数,这正是该属性的用途,在这种情况下是正确的。我不认为这个非常简单,实用,有效和预期的解决方案会出现什么问题......

特别是如果getInstance工厂做的不仅仅是实例化,而且对于所有子类都是相同的,那么“覆盖解决方案”会丢失DRY。

但是,您可能根本不需要额外的方法,只需在任何地方使用new this.constructor(args…)

var ClassFactory = constructor.bind.apply( constructor, [constructor].concat( [].slice.call( arguments ) ) );
return new ClassFactory();

看起来有点复杂,尤其是我不确定这是否适用于所有bind填充程序。请查看dynamic object construction in javascript?Use of .apply() with 'new' operator. Is this possible?