【问题标题】:Recursively call "parent" constructors in Javascript?在Javascript中递归调用“父”构造函数?
【发布时间】:2012-04-27 10:38:35
【问题描述】:

我正在开发一个 web 应用程序,它具有类似于通过基于原型的继承创建的类层次结构的东西。我们不断向一个共同的祖先“类”添加功能,因此它的构造函数签名不断扩展。

每次我们更改祖先的签名时,我们还必须将更改传播到后代的构造函数。这显然是一个可维护性问题,所以我创建了一个函数,它从arguments 对象中提取父级的参数并使用Function.apply() 调用父级。

代码如下所示:

BaseClass.prototype._super = function(args) {
    args = Array.prototype.slice.call(args, this.constructor.length);
    this.parentConstructor.apply(this, args);
};

并像这样使用:

function Child(child_arg1, child_arg2 /*, implicit parent args */) {
    this._super(arguments);
}

(我不能使用arguments.caller.arguments,因为代码是严格模式。 this.parentConstructor 由构建类层次结构的函数设置。)

不幸的是,这只适用于一层继承:例如,如果A的父类B有自己的父类C,当B调用_super时,this.parentConstructor仍然指向B,这意味着B最终会调用自己陷入无限循环。

如果我将 parentConstructor 字段与构造函数 Functions 对象一起存储(而不是在原型中),我将不得不传入当前调用函数。这将使调用的行与周围的函数超级紧密耦合,这是我试图避免的。

那么有谁知道更好的方法吗?

【问题讨论】:

  • “与周围函数超级紧密耦合”是什么意思?从Child构造函数调用this._super(Child, arguments)应该没问题吧?
  • 我只是希望能够将同一行代码复制并粘贴到所有子构造函数中,而无需更改它。就像我在 Java 中可以做的一样......

标签: javascript inheritance prototypal-inheritance


【解决方案1】:

几天前我问过a related questionKamyar Nazeri's answer帮了我很多。

避免您的问题的方法是在定义新构造函数的闭包中定义_super,以便它始终引用正确的父对象。以下模式对我来说效果很好:

var BaseClass = 
{
   create: function() // Basically a constructor
   {
      var obj = Object.create({});

      obj.someProperty = "initial value based on arguments";

      return obj;
   };
};

var Child = (function buildChild(){
   var obj    = BaseClass.create("some value", "another argument")
     , _super = Object.getPrototypeOf(obj);

   // override BaseClass.create()
   obj.create = function()
   {
      var obj = _super.create.apply(this, arguments);

      // Child specific initializations go here

      return obj;
   };

   return obj;
})(); // note that this gets called right away

var c = Child.create("some argument", "another thing");

console.log(BaseClass.isPrototypeOf(c)); // true

请注意,对于旧版浏览器,您需要为 Object.create()Object.getPrototypeOf() 提供 shims。我发现 this ECMAScript 5 shim 很有帮助。我通常只拔出我正在使用的垫片。

【讨论】:

  • 不幸的是,这是我一直试图避免的事情。我不喜欢使用函数构造对象的想法。它让 jsdoc 变得很尴尬,并且让可怜的 Eclipse 感到困惑......
  • 那么我认为您唯一的选择是使用父原型的实际名称。为什么使用函数构造对象的idea会困扰您?
  • 我认为这种编程方式非常不明确和令人困惑,不仅对人类,对文档生成器和优化编译器也是如此。此外,通过这种方式编程,“类”对象都不是真正的类,因此instanceof 运算符和许多其他工具将无法工作。
  • 我认为问题在于 JavaScript 并不是真正的基于类的语言,它是一种原型语言。 newinstanceof 似乎是用来满足不习惯原型语言的人的拐杖。 BaseClass.isPrototypeOf(c) 可以很好地替代 instanceof。当我更多地考虑这一点时,我认为模仿_super 并没有真正提供任何真正的优势。我认为最好只使用要调用其方法的对象的真实名称。这样就不需要闭包,这可能有助于编译器优化。但我不是这方面的专家。
猜你喜欢
  • 1970-01-01
  • 2018-01-31
  • 1970-01-01
  • 2011-02-12
  • 1970-01-01
  • 1970-01-01
  • 2011-03-06
  • 1970-01-01
  • 2023-03-15
相关资源
最近更新 更多