我需要在JavaScript中实现两个函数:isConstructor(x)
和constructorName(x)
isConstructor(x)
是构造函数,则 true
应返回x
,否则返回false
。例如,
isConstructor(Date) === true
isConstructor(Math.cos) === false
constructorName(x)
应返回每个正确的构造函数x
的构造函数名称。例如,
constructorName(Date) === 'Date'
我只能想到两个函数的丑陋实现,我创建了一个command
字符串
“var y = new x()”
然后在eval(command)
语句中使用try/catch
调用它。如果eval
调用成功,我将x
称为构造函数。我通过询问x
原型的类名来间接检索y
的名称,类似
var constrName = Object.prototype.toString.call(y).slice(8,-1); // extracts the `ConstrName` from `[object ConstrName]`
return constrName;
但当然,这一切都非常难看。 我该怎么做呢?
答案 0 :(得分:2)
许多人在JavaScript中说过,几乎所有函数对象都是构造函数(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function)。但是,如果要区分不能构造函数的本机函数,可以尝试:
function isConstructor(x) {
return typeof x === 'function' && typeof x.prototype !== 'undefined';
}
获取名称绝对比较棘手,您可以使用Function.prototype.toString.apply(x)
并匹配名称,但例如使用jQuery对象作为空字符串,即如果它是匿名函数。
答案 1 :(得分:1)
这个假设的问题只有一个近似值;是否可以使用new
调用函数无法在不实际尝试执行此类调用并检查TypeError的情况下可靠地完成:
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
}
这个问题:
instanceof obj === func
; 答案 2 :(得分:1)
构造函数的定义是一个实现内部[[Construct]]
方法的Object。测试它的唯一方法是将其称为构造函数,看看会发生什么。您无法使用[[Class]]
来测试Object.prototype.toString
属性以外的内部属性。
默认情况下,任何用户定义的ECMAScript函数都是构造函数,例如
function foo(){}
可以作为构造函数调用。函数是实现内部[[Call]]
方法的对象,因此 typeof 将返回“function”。但并非所有函数都是构造函数,例如
typeof document.getElementById // function
但
new document.getElementById()
会抛出一个类型错误,因为它不是构造函数。还有一些不是函数的构造函数:
typeof XMLHttpRequest // object
XMLHttpRequest 是一个构造函数,但它没有[[Call]]
因此无法作为函数调用:
var x = XMLHttpRequest() // TypeError: XMLHttpRequest isn't a function
最后,您可以尝试测试作为对象或函数的 prototype 属性,但这也不可靠,因为 prototype 属性可以添加到漂亮任何对象,主人或本地人。
所以底线是try..catch可能是唯一的方法。
答案 3 :(得分:0)
如果您不介意创建该功能的测试实例,可以执行以下操作:
function isConstructor(func) {
var t = new func();
return (t instanceof func);
}
但是:只有在构造函数不接受任何参数时才会起作用。它也可能抛出异常。如果是这样,你可以尝试其他(不太可靠)的东西,比如检查函数的名称是否以大写字母开头。
答案 4 :(得分:0)
谢谢大家的非常明确和有益的答案! 我想我现在已经理解了事实,但我也得到了一些有用的提示,指出了我还不知道的ECMAScript细节。我需要更多地深入了解文献。 再次感谢你!汤姆