一点背景知识:
ECMAScript 6+ 区分callable(可以在没有new
) and 可建造的(可以用new
) 功能:
- 通过箭头函数语法或通过类或对象文字中的方法定义创建的函数是不可建造.
- 通过创建的函数
class
语法是不可调用.
- 以任何其他方式创建的函数(函数表达式/声明,
Function
构造函数)是可调用和可构造的。
- 除非另有明确说明,否则内置函数是不可构造的。
About Function.prototype
Function.prototype
是一个所谓的内置功能 那是不可建造的。从规格来看:
未标识为构造函数的内置函数对象不会实现[[Construct]]
除非在特定函数的描述中另有说明,否则内部方法。
的价值Function.prototype
是在运行时初始化的一开始创建的。它基本上是一个空函数,并且没有明确声明它是可构造的。
如何检查函数是否是构造函数以便可以使用 new 调用它?
没有内置的方法可以做到这一点。你可以try
调用该函数new
,然后检查错误或返回true
:
function isConstructor(f) {
try {
new f();
} catch (err) {
// verify err is the expected error and then
return false;
}
return true;
}
然而,这种方法并不是安全的,因为函数可能有副作用,所以在调用之后f
,你不知道环境处于哪种状态。
另外,这只会告诉你一个函数是否can被称为构造函数,而不是如果它是intended被称为构造函数。为此,您必须查看文档或函数的实现。
Note:永远不应该有理由在生产环境中使用这样的测试。函数是否应该被调用new
应该可以从其文档中看出。
当我创建一个函数时,如何使其不是构造函数?
创建一个函数确实不是可建造的,您可以使用箭头函数:
var f = () => console.log('no constructable');
根据定义,箭头函数是不可构造的。或者,您可以将函数定义为对象或类的方法。
否则你可以检查函数是否被调用new
(或类似的东西)通过检查它this
值并在以下情况下抛出错误:
function foo() {
if (this instanceof foo) {
throw new Error("Don't call 'foo' with new");
}
}
当然,由于还有其他方法可以设置this
,可能存在误报。
Examples
function isConstructor(f) {
try {
new f();
} catch (err) {
if (err.message.indexOf('is not a constructor') >= 0) {
return false;
}
}
return true;
}
function test(f, name) {
console.log(`${name} is constructable: ${isConstructor(f)}`);
}
function foo(){}
test(foo, 'function declaration');
test(function(){}, 'function expression');
test(()=>{}, 'arrow function');
class Foo {}
test(Foo, 'class declaration');
test(class {}, 'class expression');
test({foo(){}}.foo, 'object method');
class Foo2 {
static bar() {}
bar() {}
}
test(Foo2.bar, 'static class method');
test(new Foo2().bar, 'class method');
test(new Function(), 'new Function()');