问题描述
我注意到并非所有的Javascript函数都是构造函数。
I noticed not all the Javascript functions are constructors.
var obj = Function.prototype;
console.log(typeof obj === 'function'); //true
obj(); //OK
new obj(); //TypeError: obj is not a constructor
问题1:如何检查函数是否为a构造函数,以便可以使用new调用它?
Question 1: How do I check if a function is a constructor so that it can be called with a new?
问题2:当我创建一个函数时,是否可以使它不 a构造函数?
Question 2: When I create a function, is it possible to make it NOT a constructor?
推荐答案
一点背景知识:
ECMAScript 6 +区分 callable (可以不带 new
调用)和可构造(可以用 new )函数:
ECMAScript 6+ distinguishes between callable (can be called without new
) and constructable (can be called with new
) functions:
- 通过箭头函数语法或类或对象中的方法定义创建的函数文字不可构造。
- 通过
类
语法创建的函数不可调用。 - 以任何其他方式创建的函数(函数表达式/声明,
函数
构造函数)是可调用和可构造的。 - 内置函数是除非明确说明,否则不可构建。
- Functions created via the arrow functions syntax or via a method definition in classes or object literals are not constructable.
- Functions created via the
class
syntax are not callable. - Functions created in any other way (function expression/declaration,
Function
constructor) are callable and constructable. - Built-in functions are not constructrable unless explicitly stated otherwise.
关于 Function.prototype
About Function.prototype
Function.prototype
是一个所谓的 。来自规范:
Function.prototype
is a so called built-in function that is not constructable. From the spec:
Function.prototype
的值是在最开始时创建的运行时初始化它基本上是一个空函数,并没有明确说明它是可构造的。
The value of Function.prototype
is create at the very beginning of the runtime initialization. It is basically an empty function and it is not explicitly stated that it is constructable.
没有内置的方法可以做到这一点。您可以尝试
使用 new
调用该函数,并检查错误或返回 true
:
There isn't a built-in way to do that. You can try
to call the function with new
, and either inspect the error or return true
:
function isConstructor(f) {
try {
new f();
} catch (err) {
// verify err is the expected error and then
return false;
}
return true;
}
然而,这种方法不是故障保护,因为功能可能有副作用,所以调用 f
,你不知道环境处于哪种状态。
However, that approach is not failsafe since functions can have side effects, so after calling f
, you don't know which state the environment is in.
此外,这只会告诉你函数是否可以作为构造函数调用,而不是意图作为构造函数调用。为此,你必须查看文档或函数的实现。
Also, this will only tell you whether a function can be called as a constructor, not if it is intended to be called as constructor. For that you have to look at the documentation or the implementation of the function.
注意:永远不应该有理由使用测试像生产环境中的这个。是否应该使用 new
调用函数应该可以从其文档中辨别出来。
Note: There should never be a reason to use a test like this one in a production environment. Whether or not a function is supposed to be called with new
should be discernable from its documentation.
要创建一个真正不是可构造的的函数,你可以使用箭头函数:
To create a function is truly not constructable, you can use an arrow function:
var f = () => console.log('no constructable');
箭头函数根据定义是不可构造的。或者,您可以将函数定义为对象或类的方法。
Arrow functions are by definition not constructable. Alternatively you could define a function as a method of an object or a class.
否则,您可以检查是否使用 new调用函数
(或类似的东西)通过检查它的这个
值并抛出错误,如果是:
Otherwise you could check whether a function is called with new
(or something similar) by checking it's this
value and throw an error if it is:
function foo() {
if (this instanceof foo) {
throw new Error("Don't call 'foo' with new");
}
}
当然,因为还有其他方法来设置值此
,可能存在误报。
Of course, since there are other ways to set the value of this
, there can be false positives.
示例
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()');
这篇关于如何检查Javascript函数是否为构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!