简体   繁体   English

在JavaScript中查找构造函数名称

[英]Finding a constructor name in JavaScript

I need to implement two functions in JavaScript: isConstructor(x) and constructorName(x) 我需要在JavaScript中实现两个函数: isConstructor(x)constructorName(x)

isConstructor(x) should return true in case the argument x is a constructor function, and false , otherwise. 如果参数x是构造函数,则isConstructor(x)应该返回true ,否则返回false For example, 例如,

isConstructor(Date)      ===  true
isConstructor(Math.cos)  ===  false

constructorName(x) should return the constructor name for each proper constructor function x . constructorName(x)应该为每个正确的构造函数x返回构造函数名称。 So eg 所以,例如

constructorName(Date)  ===  'Date'

I can only think of an ugly implementation for both functions, where I create a command string "var y = new x()" which is then called with an eval(command) in a try/catch statement. 我只能想到两个函数的丑陋实现,我在其中创建一个command字符串“var y = new x()”,然后在try/catch语句中使用eval(command)调用它。 If that eval call succeeds at all, I call x a constructor. 如果该eval调用完全成功,我将x称为构造函数。 And I retrieve the name of x indirectly by asking for the class name of the prototype of y , something like 我通过询问y的原型的类名来间接检索x的名称,例如

var constrName = Object.prototype.toString.call(y).slice(8,-1); // extracts the `ConstrName` from `[object ConstrName]`
return constrName;

But all this is very ugly, of course. 但当然,这一切都非常难看。 How can I do this properly? 我该怎么做呢?

Like many said in JavaScript almost any function object is a constructor ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function ). 像许多人在JavaScript中所说的几乎所有函数对象都是构造函数( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function )。 However if you want to distinguish between the native functions that can't be constructors you can try: 但是,如果要区分不能构造函数的本机函数,可以尝试:

function isConstructor(x) {
    return typeof x === 'function' && typeof x.prototype !== 'undefined';
}

Getting the name is definitely trickier, you can use the Function.prototype.toString.apply(x) and match the name, but for example with the jQuery object that would be an empty string, ie if it's anonymous function. 获取名称肯定比较棘手,您可以使用Function.prototype.toString.apply(x)并匹配名称,但例如使用jQuery对象,它将是一个空字符串,即如果它是匿名函数。

There's only an approximation to this supposed problem; 这个假设的问题只有一个近似值; whether a function can be invoked using new can't be reliably done without actually trying to perform such a call and check for a TypeError: 在没有实际尝试执行此类调用并检查TypeError的情况下,是否可以使用new调用函数无法可靠地完成:

function isConstructor(fn)
{
    try {
        var r = new fn(); // attempt instantiation
    } catch (e) {
        if (e instanceof TypeError) {
            return false; // probably shouldn't be called as constructor
        }
        throw e; // something else went wrong
    }
    return true; // some constructors may not return an instance of itself
}

The problems with this: 这个问题:

  1. Any function may choose to throw a TypeError for reasons other than the fact that it shouldn't be called as a constructor; 任何函数都可以选择抛出TypeError,原因不在于它不应该作为构造函数调用;
  2. The constructor may require certain arguments to be passed; 构造函数可能需要传递某些参数;
  3. The return value of a constructor doesn't have to meet the requirement that instanceof obj === func ; 构造函数的返回值不必满足instanceof obj === func ;的要求。
  4. The call itself causes a side effect. 呼叫本身会产生副作用。

The definition of a constructor is an Object that implements an internal [[Construct]] method. 构造函数的定义是一个实现内部[[Construct]]方法的Object。 The only way to test for that is to call it as a constructor and see what happens. 测试它的唯一方法是将其称为构造函数,看看会发生什么。 You can't test for internal properties other than the [[Class]] property using Object.prototype.toString . 您无法使用Object.prototype.toString测试[[Class]]属性以外的内部属性。

Any user defined ECMAScript function is a constructor by default, eg 默认情况下,任何用户定义的ECMAScript函数都是构造函数,例如

function foo(){}

can be called as a constructor. 可以被称为构造函数。 A function is an object that implements an internal [[Call]] method and therefore typeof will return "function". 函数是实现内部[[Call]]方法的对象,因此typeof将返回“function”。 But not all functions are constructors, eg 但并非所有函数都是构造函数,例如

typeof document.getElementById  // function

but

new document.getElementById()

will throw a type error because it's not a constructor. 将抛出一个类型错误,因为它不是一个构造函数。 There are also constructors that aren't functions: 还有一些不是函数的构造函数:

typeof XMLHttpRequest  // object

XMLHttpRequest is a constructor, but it doesn't have [[Call]] so can't be called as a function: XMLHttpRequest是一个构造函数,但它没有[[Call]]所以不能作为函数调用:

var x = XMLHttpRequest() // TypeError: XMLHttpRequest isn't a function

Lastly, you could try testing for a prototype property that is an object or function, but that also isn't reliable since a prototype property could be added to pretty much any object, host or native. 最后,您可以尝试测试作为对象或函数的原型属性,但这也不可靠,因为原型属性可以添加到几乎任何对象,主机或本机。

So the bottom line is that try..catch is probably the only way. 所以底线是try..catch可能是唯一的方法。

If you don't mind creating a test instance of the function you could do the following: 如果您不介意创建该函数的测试实例,则可以执行以下操作:

function isConstructor(func) {
    var t = new func();
    return (t instanceof func);
}

BUT: this only workes if the constructor accepts no arguments. 但是:这仅在构造函数不接受任何参数时才起作用。 It might as well throw an exception. 它也可能抛出异常。 If it does you could try other (not so reliable) things, like checking if the name of the function starts with an uppercase Letter. 如果是这样,你可以尝试其他(不那么可靠)的东西,比如检查函数的名称是否以大写字母开头。

Thank you all for your very clear and helpful answers! 谢谢大家的非常明确和有益的答案! I think I do understand the facts now, but I also got some helpful hints that pointed me to ECMAScript details I didn't know, yet. 我想我现在明白了事实,但我也得到了一些有用的提示,指出我还不知道的ECMAScript细节。 I need to dive into the literature a little more. 我需要更多地深入了解文献。 Thank you, again! 再次感谢你! Tom 汤姆

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM