Javascript:如何获取对象的原型链构造函数名称列表?

时间:2014-10-05 00:03:02

标签: javascript node.js inheritance prototype

我最近遇到了一个有趣的问题。我正在开发一些现有的代码,无论好坏,通常有几个级别的原型继承以各种各种对象的构造函数结尾。这些中的每一个最终都来自单个基类'。

每个构造函数都遵循以下继承模式,其中Sub是子类,Super是它的直接原型:

function Sub(/*args*/) {
    Super.call(this,/*args*/);
}

Sub.prototype = Object.create(Super.prototype);

这种模式一直持续到单个基类。

发现我们需要为原型链上的每个对象存储构造函数名称列表非常有益,我想出了基类的以下代码添加,它使用了calleearguments对象的caller属性:

var curConstructor = arguments.callee;
this.constructorList = [curConstructor.name];

while(curConstructor.caller && curConstructor.caller.name !== ''){
    curConstructor = curConstructor.caller;
    this.constructorList.push(curConstructor.name);
}

这个问题的主要问题是,如果对象是在匿名函数(或全局范围)内构造的,只有才有效。例如,假设我有一个构造函数SubA1,原型SubA带有原型Base,如果我这样做:

function() {
  var aOk = new SubA1();
  function oops() {
    var aNotOk = new SubA1();
  }
  oops();
}

aOk的构造函数列表是:[Base,SubA,SubA1],这就是我想要的。

aNotOk的构造函数列表最终为:[Base,SubA,SubA1,oops]

Here's a plunker

我可以通过让每个构造函数将它们的名称添加到构造函数列表本身来修复它,但是存在一些问题,尤其是将代码添加到代码中的巨大痛苦(以及调试/维护噩梦)。许多构造函数中的每一个。

有没有一种优雅的方法来实现这一目标?

请注意,尽管上面的问题是在更广泛的意义上提出的,而不是Node.js特有的,但我实际上是在Node.js环境中使用代码。因此,欢迎特定于Node的解决方案。

更新

在我的特定情况下,所有构造函数都在命名空间内。所以我实际上可以通过执行检查来确保函数名称存在于命名空间中,然后再将其添加到constructorList来解决问题。

基本上,我可以这样做:

var curConstructor = arguments.callee;
this.constructorList = [curConstructor.name];

while(curConstructor.caller){
    curConstructor = curConstructor.caller;

    // Exit if the function name isn't part of the namespace
    if(typeof namespace[curConstructor.name] !== 'function') break;

    this.constructorList.push(curConstructor.name);
}

当然,这不会在一般意义上解决它,并且它并不完美。例如,如果调用new SubA1的函数恰好与命名空间中的一个构造函数具有相同的名称,它将抛出该列表。在我的特定情况下,由于构造函数遵循唯一的命名模式,因此这种情况极不可能发生。

我知道arguments.callee已被弃用,Object.constructor不值得信赖(它无法让我得到我想要的东西),但我不知道有任何其他方法可以获得通过修改基类'类链中每个构造函数的名称。仅

1 个答案:

答案 0 :(得分:2)

当它们被注册为原型的属性时,该函数获取原型链的所有构造函数:

function getConstructorChain(obj, type) {
    var cs = [], pt = obj;
    do {
       if (pt = Object.getPrototypeOf(pt)) cs.push(pt.constructor || null);
    } while (pt != null);
    return type == 'names' ? cs.map(function(c) {
        return c ? c.toString().split(/\s|\(/)[1] : null;
    }) : cs;
}

不带参数type返回一个函数数组,其中type = 'names'是一个函数名字符串数组。

工作FIDDLE with a HTMLDivElement object as example here。使用控制台。