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

我最近遇到一个有趣的问题。 我正在开发一些现有的代码,无论好坏,通常有几个级别的原型inheritance结束于各种各样的对象的构造函数。 其中每一个最终都从一个基础“类”inheritance。

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

 function Sub(/*args*/) { Super.call(this,/*args*/); } Sub.prototype = Object.create(Super.prototype); 

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

发现这对于我们的需要来说是非常有益的,为每个对象在原型链上存储一个构造函数名称列表,我为基类提供了以下代码,它使用了arguments对象的calleecaller属性:

 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]

这里是一个笨蛋

我可以通过让每个构造函数将它们的名称添加到构造函数列表中来解决这个问题,但是有几个问题,其中最重要的就是巨大的痛苦(和debugging/维护噩梦),将代码添加到每个许多构造函数。

有没有一个优雅的方式来实现这一目标?

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

更新:

在我的具体情况下,所有的构造函数都在一个名字空间内。 所以我实际上可以通过执行一个检查以确保函数名称存在于名称空间中,然后将其添加到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是不可信的(它不能得到我想要的东西),但我不知道任何其他方式通过修改每个构造函数的名称只有基础“阶级”。

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

 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'是一个函数名称string数组。

以HTMLDivElement对象的工作FIDDLE为例 。 使用控制台。