背景的一點點:創建
關於Function.prototype
Function.prototype
是所謂的built-in functionthat is not constructable。從規格:
未標識爲構造函數的內置函數對象不實現[[Construct]]
內部方法,除非在特定函數的說明中另有說明。
Function.prototype
的值是在運行時初始化時創建的。它基本上是一個空的函數,並沒有明確說明它是可以構造的。
我如何檢查如果一個函數是一個構造函數,以便它可以用一個新的被稱爲?
有沒有一種內置的方式來做到這一點。您可以try
調用函數new
,並且或者檢查錯誤或返回true
:
function isConstructor(f) {
try {
new f();
} catch (err) {
// verify err is the expected error and then
return false;
}
return true;
}
然而,這種做法是不是失效保護功能,因爲可以有副作用,因此調用f
後,你不知道環境所處的狀態。
而且,這隻會告訴你是否一個功能可以被稱爲構造函數,而不是是否是打算被稱爲構造函數。爲此,您必須查看文檔或函數的實現。
注意:在生產環境中不應該有像這樣的測試。從文檔中可以看出,是否應該使用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
,可能有誤報。
例子
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()');
有趣的是'Function'和'Function.prototype'是唯一不是構造函數的函數嗎? – Adam
功能是一個construtor。新函數();作品。 –
只需檢查該類型是否爲函數。 – rlemon