为什么我们使用`Boy.prototype = new Human;`来模拟继承?

时间:2011-05-13 11:23:25

标签: javascript ecmascript-5

我不明白为什么每个人都在使用Boy.prototype = new Human;来模拟继承。看,我们想要的是A的功能吗?我们可以在没有实例化新A的情况下做到这一点(实际上,实例化一个新的A会给我们带来不良结果,因为我们实际上正在运行不是我们想要的实例化函数)

那么这不是一个更好的解决方案吗?

for (var prop_name in Human.prototype) {
Object.defineProperty(
          Boy.prototype,
          prop_name,
          Object.getOwnPropertyDescriptor(Human.prototype,prop_name)
        );
}

假设我们是那么特别,并且不仅希望Human.prototype中的可枚举属性,我们仍然可以通过使用Object.getOwnPropertyNames并在原型链上调用它来实现它,而原型链又可以通过{{1 }}

那么当我们有更好的选择时,做Object.getPrototypeOf来模拟继承的好处究竟是什么?

2 个答案:

答案 0 :(得分:4)

  • 它正确设置原型链,意味着instanceofisPrototypeOf()将起作用
  • 不那么冗长

当您只是使用它来创建原型对象时,有一些简单但丑陋的变通方法可以防止构造函数执行其通常的初始化。例如,您可以检查参数:

function Boy(name) {
    if (arguments.length == 1) {
        this.name = name;
        // Do other initialization
    }
}

...或将初始化移动到必须明确调用的单独方法中:

function Boy(name) {}

Boy.prototype.init = function(name) {
    this.name = name;
    // Do other initialization
}

这有明显的缺点,要求您在创建新的init()时记得致电Boy

在ECMAScript 5环境中(例如,大多数浏览器的当前版本),更好的选项可能是ECMAScript 5的Object.create(),它允许您创建一个直接从另一个对象继承并设置原型链的对象为了你。这可以在非ES5环境中进行模拟(但仅约为:Object.defineProperty in ES5?):

if (!Object.create) {
    Object.create = function(o) {
        function F() {}
        F.prototype = o;
        return new F();
    }; 
}

答案 1 :(得分:4)

更好的选择是创建一个中间来保存原型。

function extend(clazz, superclass) {
    var intermediate = function() {};
    intermediate.prototype = superclass.prototype;
    clazz.prototype = new intermediate();
    // Following line is optional, but useful
    clazz.prototype.constructor = clazz;
}

这可以避免不必要的复制,但仍然意味着您不需要实例化将在其构造函数中起作用的对象。它还设置了原型链,以便您可以使用instanceof。它也不会导致超类原型污染,这是一些遗传反模式可以实现的。

为了完整性,您的子类应该在其构造函数中调用超类构造函数,您可以使用Superclass.call(this);

编辑:从ES5开始,您可以用

替换extend的来电
Subclass.prototype = Object.create(Superclass.prototype);

做同样的事情。