[英]Javascript: How to get a list of an object's prototype chain constructor names?
I recently encountered an interesting problem. 我最近遇到了一个有趣的问题。 I am developing with some existing code where, for better or worse, there are often several levels of prototypical inheritance ending in constructors for all kinds of various objects.
我正在开发一些现有的代码,无论好坏,通常有几个级别的原型继承以各种各种对象的构造函数结尾。 Each of these ultimately inherit from a single base 'class'.
这些中的每一个最终都来自单个基础“类”。
Each constructor follows the following inheritance pattern, where Sub
is a subclass and Super
is it's immediate prototype: 每个构造函数都遵循以下继承模式,其中
Sub
是子类, Super
是它的直接原型:
function Sub(/*args*/) {
Super.call(this,/*args*/);
}
Sub.prototype = Object.create(Super.prototype);
This pattern continues all the way up to the single base class. 这种模式一直持续到单个基类。
Discovering that it would be incredibly beneficial for our needs to store a list of constructor names for each object up the prototype chain, I came up with the following code addition for the base class, which uses the callee
and caller
properties of the arguments object: 发现我们需要为原型链上的每个对象存储构造函数名称列表非常有益,我想出了基类的以下代码添加,它使用了arguments对象的
callee
和caller
属性:
var curConstructor = arguments.callee;
this.constructorList = [curConstructor.name];
while(curConstructor.caller && curConstructor.caller.name !== ''){
curConstructor = curConstructor.caller;
this.constructorList.push(curConstructor.name);
}
The main issue with this, is it only works if the object was constructed inside of an anonymous function (or global scope). 这个问题的主要问题是它只在对象是在匿名函数(或全局范围)内构造时才有效。 For instance, assuming I have a constructor
SubA1
with prototype SubA
with prototype Base
, if I do this: 例如,假设我有一个带有原型
Base
原型SubA
的构造函数SubA1
,如果我这样做:
function() {
var aOk = new SubA1();
function oops() {
var aNotOk = new SubA1();
}
oops();
}
aOk
's constructor list is: [Base,SubA,SubA1]
, which is what I want. aOk
的构造函数列表是: [Base,SubA,SubA1]
,这就是我想要的。
aNotOk
's constructor list ends up as: [Base,SubA,SubA1,oops]
. aNotOk
的构造函数列表最终为: [Base,SubA,SubA1,oops]
。
I could fix it by having each constructor add their name to the constructor list themselves, but there are several problems with that, not least of which is the tremendous pain (and debugging / maintenance nightmare) it would be to add code to each of the many many constructor functions. 我可以通过让每个构造函数将它们的名称添加到构造函数列表本身来修复它,但是存在一些问题,其中最重要的是将代码添加到每个构建器的巨大痛苦(以及调试/维护噩梦)。许多构造函数。
Is there an elegant way to achieve this? 有一种优雅的方式来实现这一目标吗?
Note that although the above question was asked in a more general sense, and not specific to Node.js, I am actually working with code in a Node.js environment. 请注意,虽然上面的问题是在更广泛的意义上提出的,而不是Node.js特有的,但我实际上是在Node.js环境中使用代码。 Therefore, solutions specific to Node are welcome.
因此,欢迎特定于Node的解决方案。
In my particular case, all of the constructors are within a namespace. 在我的特定情况下,所有构造函数都在命名空间内。 So I can actually solve the problem by performing a check to make sure that the function name exists in the namespace before adding it to the
constructorList
. 所以我实际上可以通过执行检查来确定函数名称是否存在于命名空间中,然后再将其添加到
constructorList
。
Basically, I can do this: 基本上,我可以这样做:
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);
}
This won't solve it in a generic sense though of course, and it isn't perfect. 当然,这不会在一般意义上解决它,并且它并不完美。 If the function which calls
new SubA1
for example just happens to have the same name as one of the constructors in the namespace, it will throw the list off. 例如,如果调用
new SubA1
的函数恰好与命名空间中的一个构造函数具有相同的名称,它将抛出该列表。 In my particular case, since the constructors follow a unique naming pattern, that occurrence is extremely unlikely. 在我的特定情况下,由于构造函数遵循唯一的命名模式,因此这种情况极不可能发生。
I am aware that arguments.callee
is deprecated, and that Object.constructor
is not trustworthy (it doesn't get me what I want anyway), but I am unaware of any other way to get names of each constructor in the chain by modifying the base 'class' only. 我知道
arguments.callee
已被弃用,并且Object.constructor
不值得信任(它无法得到我想要的东西),但我不知道通过修改获取链中每个构造函数的任何其他方法只是基础'类'。
This function gets all constructors of a prototype chain, when they are registered as a property of the prototype: 当这些函数被注册为原型的属性时,它将获取原型链的所有构造函数:
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;
}
Without argument type
an array of functions is returned, with type = 'names'
an array of function-name strings. 如果没有参数
type
,则返回一个函数数组,其中type = 'names'
是一个函数名字符串数组。
Working FIDDLE with a HTMLDivElement object as example here . 以HTMLDivElement对象为例,使用FIDDLE作为示例 。 Use console.
使用控制台。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.