【问题标题】:Does calling Class.prototype = new MyClass() ensure superclass is reinstantiated each time?调用 Class.prototype = new MyClass() 是否确保每次都重新实例化超类?
【发布时间】:2013-12-18 19:16:25
【问题描述】:

我正在使用:

var ReportsServiceCall = function () { };

ReportsServiceCall.prototype = new ServiceCall();

使用此代码,每次创建 new ReportsServiceCall 时,ServiceCall 是否都是一个新实例?我需要这样。

【问题讨论】:

  • 我想他是在问它是否是每个新 ReportsServiceCall 上的新 ServiceCall 实例。
  • 是的,我追求的是 regulus 所描述的。
  • 你父母的实例变量现在放在了Child的原型上,必须创建一个Parent的实例来设置Child 50%的继承,这不是一个好方法。更多关于原型的信息:stackoverflow.com/a/16063711/1641941

标签: javascript prototype javascript-objects


【解决方案1】:

不是真的。

一个ReportsServiceCall 是一个 ServiceCall,但是用new 创建一个ReportsServiceCall 并不能让它有自己的属性,这些属性在ServiceCall 的构造函数中分配。

看下面的例子:

var ServiceCall=function () {
    this.Id=Math.random();
};

var ReportsServiceCall=function () {
};

ReportsServiceCall.prototype=new ServiceCall();

var x=new ReportsServiceCall();
var y=new ReportsServiceCall();

alert(x.Id===y.Id); // true .. so, what Id for?

其中一个解决方案是:

var ReportsServiceCall=function () {
    ServiceCall.apply(this, arguments);
};

【讨论】:

  • ServiceCall.apply(this, arguments) 并不理想。父构造函数不太可能将相同的参数发送给子构造函数。提供最小的解决方案可能更好。
【解决方案2】:

没有

正如您所写,原型只设置一次。但是,这不是一个很好的写法。

我会这样写

var ReportsServiceCall = function () {

  // parent constructor; optional
  ServiceCall.call(this);
};

// setup prototype; see comment below
ReportsServiceCall.prototype = Object.create(ServiceCall.prototype, {
  constructor: {
    value: ReportsServiceCall,
    enumerable: false,
    writable: true,
    configurable: true
  }
});

注意:除了设置super_,这就是node.js 在其util.inherits 函数中进行普通继承的方式。

一旦您了解了它的工作原理,这是非常有效的技术。

【讨论】:

  • 我同意将 Object.create 用于原型部分,+1 用于重新使用 ServiceCall 构造函数。 Object.create 的第二个参数不能在旧版浏览器中使用,即使您对其进行了填充。对于较旧的浏览器,可以这样做:ReportsServiceCall.prototype = Object.create(ServiceCall.prototype);ReportsServiceCall.prototype.constructor = ReportsServiceCall;
  • 谢谢大家,看来我要放弃对 ie8 的支持,然后继续使用这个。 (哦,我是如何等待这一天的)
【解决方案3】:

原型只是一个对象,将被ReportsServiceCall 的所有实例共享。如果您需要为每个 ReportsServiceCall 实例调用 ServiceCall 构造函数,您可以这样做:

function ReportsServiceCall() {
  ServiceCall.call(this);
};
ReportsServiceCall.prototype = new ServiceCall();
ReportsServiceCall.prototype.constructor = ReportsServiceCall;

【讨论】:

    【解决方案4】:

    使用此代码,ServiceCall 是否每次都是一个新实例?

    不,这不是设置继承的好方法。在您调用new ServiceCall 的那一刻,您实际上不想创建ServiceCall 的实例(如果构造函数需要参数,您将传递哪些参数?)。您真正想要的只是将ServiceCall 的原型添加到ReportsServiceCall 的原型链中。

    您应该改用Object.create 并在子类构造函数中调用超类构造函数:

    var ReportsServiceCall = function () {
        ServiceCall.call(this);
    };
    
    ReportsServiceCall.prototype = Object.create(ServiceCall.prototype);
    

    有关此模式的详细说明,请参阅 Benefits of using `Object.create` for inheritance

    【讨论】:

    • +1 由于 javascript 接受可变参数,可能要使用 apply .. ?
    • @KenKin,父构造函数不太可能接受发送给子构造函数的完全相同的参数。
    • @FelixKling,您可能需要考虑将{constructor: {value: ReportsServiceCall}} 传递给Object.create。否则你会得到(new ReportServiceCall).constructor.name; // ""
    • @maček: 嗯.. 参数顺序的不一致可能是一个有争议的设计问题..
    • @maček 因为 JavaScript 没有将参数命名为(例如)python,所以我通常传递一个 args 对象。这个对象可以通过构成某个进程的函数链传递,每个函数读取和设置它需要的任何内容。你不能做someFunction(spacing=15, step=2);,但你可以做someFunction({spacing:15,step:2});。当您使用中介模式并且不确定某个函数中的下一个函数是什么时,这特别方便。
    【解决方案5】:

    恕我直言,因为您只设置了一次原型

    【讨论】:

    • 好吧,只要这是一个诚实的意见:)
    猜你喜欢
    • 2019-02-12
    • 1970-01-01
    • 2020-11-17
    • 1970-01-01
    • 2016-10-21
    • 1970-01-01
    • 1970-01-01
    • 2018-05-26
    • 2018-12-09
    相关资源
    最近更新 更多