我想检查一个JavaScript值是否是一个构造函数,也就是说,它是否有一个[ constructor ]内部方法。
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中,可能在某些草稿或建议的特性中?
发布于 2016-09-05 18:50:35
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,
如果目标具有[构造]内部方法,则
因此,代码创建一个代理对象,其目标是我们要检查的值,其处理程序具有不抛出的构造陷阱。
这样,如果代理是构造函数(即测试的值是构造函数),实例化时它将在陷阱中运行代码,而不是将操作重定向到目标,并且不会抛出。如果代理不是构造函数(即测试值两者都不是),实例化时它将抛出一个错误。
不过有个小问题。在创建代理时,目标必须是非代理对象,或者是未撤销的代理对象。否则,它会抛出,因此上面的代码认为它是一个非构造函数。
对于原语来说,这是可以的,因为它们不能是构造函数。但是,被撤销的代理可以是构造函数,我们不能正确地测试它们。
为了以不同的方式处理这种情况,您可能需要检测该值是否为已撤销的代理。。
https://stackoverflow.com/questions/39334278
复制相似问题