gpt4 book ai didi

javascript - 检查对象是否是构造函数 - IsConstructor

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:00:44 24 4
gpt4 key购买 nike

我想检查一个 JavaScript 值是否是一个构造函数,也就是说,它是否有一个 [[Construct]] 内部方法。

ECMAScript 定义 IsConstructor ,正是这样做的,但这是一个内部操作。

所以我想效仿一下。我考虑过在 try 语句中尝试实例化或子类化,但两者都不能在所有情况下可靠地工作。

function isConstructor(value) {
try {
return new value(), true;
} catch(err) {
return false;
}
}

function isConstructor(value) {
try {
return new value(), true;
} catch(err) {
return false;
}
}
var tests = 0,
failed = 0;
function test(value, expected, msg) {
++tests;
try {
var result = isConstructor(window.eval(value));
} catch(err) {
result = err;
}
if(result !== expected) {
++failed;
console.log('Testing: ' + value + '\nMessage: ' + msg + '\nResult: ' + result + '\nExpected: ' + expected);
}
}
function testEnd() {
console.log(failed + ' out of ' + tests + ' tests failed.');
}
test('undefined', false, 'undefined is not a constructor');
test('null', false, 'null is not a constructor');
test('true', false, 'booleans are not constructors');
test('0', false, 'numbers are not constructors');
test('"abc"', false, 'strings are not constructors');
test('Symbol()', false, 'symbols are not constructors');
test('({})', false, '{} is not a constructor');
test('[]', false, 'arrays are not constructors');
test('(function(){})', true, 'normal functions are constructors');
test('(function(){throw TypeError()})', true, 'normal functions are constructors');
test('(function(){}.bind())', true, 'bounded normal functions are constructors');
test('() => {}', false, 'arrow functions are not constructors');
test('((() => {}).bind())', false, 'bounded arrow functions are not constructors');
test('(function*(){})', false, 'generator functions are not constructors');
test('(function*(){}.bind())', false, 'bounded generator functions are not constructors');
test('(class{})', true, 'classes are constructors');
test('(class extends function(){}{})', true, 'classes are constructors');
test('new Proxy([],{})', false, 'proxies whose target is not constructor are not constructors');
test('new Proxy(function(){},{})', true, 'proxies whose target is a constructor are constructors');
test('new Proxy(function(){},{get:()=>{throw TypeError()}})', true, 'proxies whose target is a constructor are constructors');
test('new Proxy(function(){},{construct:()=>{throw TypeError()}})', true, 'proxies whose target is a constructor are constructors');
test('var r1 = Proxy.revocable([],{}); r1.proxy', false, 'revocable proxies whose target is not a constructor are notconstructors');
test('r1.revoke(); r1.proxy', false, 'revoked proxies whose target was not a constructor are not constructors');
test('var r2 = Proxy.revocable(function(){},{}); r2.proxy', true, 'revocable proxies whose target is a constructor are constructors');
test('r2.revoke(); r2.proxy', true, 'revoked proxies whose target was a constructor are constructors');
testEnd();

function isConstructor(value) {
if(value === null) return false;
try {
return class extends value {}, true;
} catch(err) {
return false;
}
}

function isConstructor(value) {
if(value === null) return false;
try {
return class extends value {}, true;
} catch(err) {
return false;
}
}
var tests = 0,
failed = 0;
function test(value, expected, msg) {
++tests;
try {
var result = isConstructor(window.eval(value));
} catch(err) {
result = err;
}
if(result !== expected) {
++failed;
console.log('Testing: ' + value + '\nMessage: ' + msg + '\nResult: ' + result + '\nExpected: ' + expected);
}
}
function testEnd() {
console.log(failed + ' out of ' + tests + ' tests failed.');
}
test('undefined', false, 'undefined is not a constructor');
test('null', false, 'null is not a constructor');
test('true', false, 'booleans are not constructors');
test('0', false, 'numbers are not constructors');
test('"abc"', false, 'strings are not constructors');
test('Symbol()', false, 'symbols are not constructors');
test('({})', false, '{} is not a constructor');
test('[]', false, 'arrays are not constructors');
test('(function(){})', true, 'normal functions are constructors');
test('(function(){throw TypeError()})', true, 'normal functions are constructors');
test('(function(){}.bind())', true, 'bounded normal functions are constructors');
test('() => {}', false, 'arrow functions are not constructors');
test('((() => {}).bind())', false, 'bounded arrow functions are not constructors');
test('(function*(){})', false, 'generator functions are not constructors');
test('(function*(){}.bind())', false, 'bounded generator functions are not constructors');
test('(class{})', true, 'classes are constructors');
test('(class extends function(){}{})', true, 'classes are constructors');
test('new Proxy([],{})', false, 'proxies whose target is not constructor are not constructors');
test('new Proxy(function(){},{})', true, 'proxies whose target is a constructor are constructors');
test('new Proxy(function(){},{get:()=>{throw TypeError()}})', true, 'proxies whose target is a constructor are constructors');
test('new Proxy(function(){},{construct:()=>{throw TypeError()}})', true, 'proxies whose target is a constructor are constructors');
test('var r1 = Proxy.revocable([],{}); r1.proxy', false, 'revocable proxies whose target is not a constructor are notconstructors');
test('r1.revoke(); r1.proxy', false, 'revoked proxies whose target was not a constructor are not constructors');
test('var r2 = Proxy.revocable(function(){},{}); r2.proxy', true, 'revocable proxies whose target is a constructor are constructors');
test('r2.revoke(); r2.proxy', true, 'revoked proxies whose target was a constructor are constructors');
testEnd();

有什么方法可以可靠地测试它吗?如果不在 ES6 或 ES7 中,可能在某些草案或提议的功能中?

最佳答案

这是基于 Jason Orendorff 发布的代码在 esdicuss .

function isConstructor(value) {
try {
new new Proxy(value, {construct() { return {}; }});
return true;
} catch (err) {
return false;
}
}

function isConstructor(value) {
try {
new new Proxy(value, {construct() { return {}; }});
return true;
} catch (err) {
return false;
}
}
var tests = 0,
failed = 0;
function test(value, expected, msg) {
++tests;
try {
var result = isConstructor(window.eval(value));
} catch(err) {
result = err;
}
if(result !== expected) {
++failed;
console.log('Testing: ' + value + '\nMessage: ' + msg + '\nResult: ' + result + '\nExpected: ' + expected);
}
}
function testEnd() {
console.log(failed + ' out of ' + tests + ' tests failed.');
}
test('undefined', false, 'undefined is not a constructor');
test('null', false, 'null is not a constructor');
test('true', false, 'booleans are not constructors');
test('0', false, 'numbers are not constructors');
test('"abc"', false, 'strings are not constructors');
test('Symbol()', false, 'symbols are not constructors');
test('({})', false, '{} is not a constructor');
test('[]', false, 'arrays are not constructors');
test('(function(){})', true, 'normal functions are constructors');
test('(function(){throw TypeError()})', true, 'normal functions are constructors');
test('(function(){}.bind())', true, 'bounded normal functions are constructors');
test('() => {}', false, 'arrow functions are not constructors');
test('((() => {}).bind())', false, 'bounded arrow functions are not constructors');
test('(function*(){})', false, 'generator functions are not constructors');
test('(function*(){}.bind())', false, 'bounded generator functions are not constructors');
test('(class{})', true, 'classes are constructors');
test('(class extends function(){}{})', true, 'classes are constructors');
test('new Proxy([],{})', false, 'proxies whose target is not constructor are not constructors');
test('new Proxy(function(){},{})', true, 'proxies whose target is a constructor are constructors');
test('new Proxy(function(){},{get:()=>{throw TypeError()}})', true, 'proxies whose target is a constructor are constructors');
test('new Proxy(function(){},{construct:()=>{throw TypeError()}})', true, 'proxies whose target is a constructor are constructors');
test('var r1 = Proxy.revocable([],{}); r1.proxy', false, 'revocable proxies whose target is not a constructor are notconstructors');
test('r1.revoke(); r1.proxy', false, 'revoked proxies whose target was not a constructor are not constructors');
test('var r2 = Proxy.revocable(function(){},{}); r2.proxy', true, 'revocable proxies whose target is a constructor are constructors');
test('r2.revoke(); r2.proxy', true, 'revoked proxies whose target was a constructor are constructors');
testEnd();

代理对象只有在其初始目标是构造函数时才是构造函数。来自 ProxyCreate ,

If target has a [[Construct]] internal method, then

  • Set the [[Construct]] internal method of P as specified in 9.5.14.

因此,代码创建了一个代理对象,其目标是我们要检查的值,并且其处理程序具有不抛出的构造陷阱。

这样,如果代理是一个构造函数(即被测试的值是一个构造函数),在实例化时它将运行陷阱中的代码而不是将操作重定向到目标,并且它不会抛出。如果代理不是构造函数(即测试值都不是),则在实例化时会抛出错误。

虽然有一点问题。创建代理时,目标必须是非代理对象或未撤销的代理对象。否则,它会抛出异常,因此上面的代码将其视为非构造函数。

这对于基元来说是可以的,因为它们不能是构造函数。然而,被撤销的代理可以是构造函数,也可以不是构造函数,我们无法正确测试它们。

您可能想要 detect if the value is a revoked proxy为了以不同的方式处理这种情况。

关于javascript - 检查对象是否是构造函数 - IsConstructor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39334278/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com