如何检查值是否是JavaScript中的对象?
当前回答
您可以使用Object.prototype的toString()方法轻松完成此操作
if(Object.prototype.toString.call(variable) == "[object Object]"){
doSomething();
}
or
if(Object.prototype.toString.call(variable).slice(8,-1).toLowerCase() == "object"){
doSomething();
}
其他回答
我的上帝,其他答案太混乱了。
简短回答
typeof anyVar==“对象”&&anyVar对象实例&&!(数组的anyVar实例)
要测试这一点,只需在chrome控制台中运行以下语句。
案例1。
var anyVar = {};
typeof anyVar == 'object' && anyVar instanceof Object && !(anyVar instanceof Array) // true
案例2。
anyVar = [];
typeof anyVar == 'object' && anyVar instanceof Object && !(anyVar instanceof Array) // false
案例3。
anyVar = null;
typeof anyVar == 'object' && anyVar instanceof Object && !(anyVar instanceof Array); // false
解释
好吧,我们来分解一下
typeof anyVar==“object”从三个候选项中返回true-[]、{}和null,
anyVar instanceof Object将这些候选对象缩小到两个-[],{}
!(anyVar instanceof Array)仅限于一个-{}
请滚鼓!
至此,您可能已经学会了如何在Javascript中检查Array。
检查值类型的最合理方法似乎是typeof运算符。唯一的问题是它已经严重损坏:
它为null返回“object”,这属于null类型。它为属于Object类型的可调用对象返回“函数”。对于非标准的不可调用对象,它可以返回(几乎)它想要的任何内容。例如,IE似乎喜欢“未知”。唯一被禁止的结果是“函数”和原始类型。
typeof仅对非空基元可靠。因此,检查值是否为对象的一种方法是确保typeof返回的字符串与原语不对应,并且对象不为空。然而,问题是未来的标准可能会引入一种新的原始类型,我们的代码会将其视为一个对象。新类型并不经常出现,但例如ECMAScript 6引入了Symbol类型。
因此,我只推荐结果随值是否为对象而变化的方法,而不是typeof。以下是
测试值是否属于Object类型的正确方法的全面但不详尽的列表。
对象构造函数Object构造函数将传递的参数强制为对象。如果它已经是一个对象,则返回相同的对象。因此,您可以使用它将值强制转换为对象,并将该对象与原始值严格比较。以下函数需要ECMAScript 3,它引入了==:函数isObject(value){/*需要ECMAScript 3或更高版本*/return Object(value)==value;}我喜欢这种方法,因为它简单且自我描述,类似的检查也适用于布尔值、数字和字符串。但是,请注意,它依赖于全局对象,而不是隐藏或更改。施工人员实例化构造函数时,它可以返回一个不同于刚刚创建的实例的值。但该值将被忽略,除非它是一个对象。以下函数需要ECMAScript 3,它允许构造函数返回非对象。在抛出错误的ECMAScript 3之前,try语句当时不存在。函数isObject(value){/*需要ECMAScript 3或更高版本*/return new函数(){return value;}()==value;}虽然比上一个例子简单一点,但这个例子不依赖任何全局属性,因此可能是最安全的。此值旧的ECMAScript规范要求此值为对象。ECMAScript 3引入了Function.prototype.call,它允许调用具有任意此值的函数,但强制为对象。ECMAScript 5引入了一个严格模式,删除了这种行为,但在草率模式下,我们仍然可以(但可以说不应该)依赖它。函数isObject(value){/*需要ECMAScript 3或更高版本处于草率模式*/return函数(){return this==value;}.call(value);}[[原型]]所有普通对象都有一个名为[[Prototype]]的内部槽,其值决定它从哪个其他对象继承。该值只能是对象或null。因此,您可以尝试创建继承自所需值的对象,并检查其是否有效。Object.create和Object.getPrototypeOf都需要ECMAScript 5。函数isObject(value){/*需要ECMAScript 5或更高版本*/尝试{对象.create(value);返回值!==无效的}捕获(错误){return false;}}函数isObject(value){/*需要ECMAScript 5或更高版本*/函数构造函数(){}Constructor.prototype=值;return Object.getPrototypeOf(new Constructor())==值;}一些新的ECMAScript 6方式ECMAScript 6引入了一些新的间接方法来检查值是否为对象。他们使用前面看到的方法将值传递给一些需要对象的代码,该对象封装在try语句中以捕获错误。一些隐藏的例子,不值得评论函数isObject(value){/*需要ECMAScript 6或更高版本*/尝试{Object.setPrototypeOf({},值);返回值!==无效的}捕获(错误){return false;}}函数isObject(value){/*需要ECMAScript 6或更高版本*/尝试{新的WeakSet([value]);返回true;}捕获(错误){return false;}}
注意:我有意跳过了一些方法,例如Object.getPrototypeOf(value)(ES5)和Reflect方法(ES6),因为它们调用了可能会做坏事的基本内部方法,例如,如果value是代理。出于安全原因,我的示例仅引用值,而不直接访问它。
表演
今天2020.09.26我在Chrome v85、Safari v13.1.2和Firefox v80上对MacOs HighSierra 10.13.6进行了测试,以确定所选的解决方案。
后果
解决方案C和H在所有情况下在所有浏览器上都是快速/最快的在所有情况下,解决方案D和G在所有浏览器上都是慢/最慢的
细节
我为解决方案执行3个测试用例A.BCDEFGH我JKLMNOPQRSTU五、
对于小对象-您可以在此处运行对于大型对象-您可以在此处运行没有对象-你可以在这里运行
下面的代码片段介绍了解决方案之间的差异。解决方案A-G为Matt Fenwick描述的选定案例提供了正确的答案
// https://stackoverflow.com/a/14706877/860099函数A(x){return x===对象(x);};// https://stackoverflow.com/a/42250981/860099函数B(x){return _.isObject(x);}// https://stackoverflow.com/a/34864175/860099函数C(x){返回x!=null&&(typeof x===“对象”| | typeof x====“函数”);}// https://stackoverflow.com/a/39187058/860099函数D(x){return new函数(){return x;}()==x;}// https://stackoverflow.com/a/39187058/860099函数E(x){return函数(){return this==x;}.call(x);}// https://stackoverflow.com/a/39187058/860099函数F(x){/*需要ECMAScript 5或更高版本*/尝试{对象.create(x);返回x!==无效的}捕获(错误){return false;}}// https://stackoverflow.com/a/39187058/860099函数G(x){/*需要ECMAScript 5或更高版本*/函数构造函数(){}Constructor.prototype=x;return Object.getPrototypeOf(new Constructor())==x;}// https://stackoverflow.com/a/8511332/860099函数H(x){返回类型x=='对象'&&x!==无效的}// https://stackoverflow.com/a/25715455/860099函数I(x){return(typeof x==“object”&&!Array.isArray(x)&&x!==空);};// https://stackoverflow.com/a/22482737/860099函数J(x){return x instanceof Object;}// https://stackoverflow.com/a/50712057/860099函数K(x){设t=JSON.stringify(x);返回t?t[0]==“{”:false;}// https://stackoverflow.com/a/13356338/860099函数L(x){return Object.pr原型.toString.call(x)==“[对象对象]”;};// https://stackoverflow.com/a/46663081/860099函数M(o,strict=true){如果(o==null | | o==未定义){return false;}const instanceOfObject=o instanceof Object;const typeOfObject=typeof o==“对象”;constconstructorUndefined=o.constructor===未定义;constconstructorObject=o.constructor==对象;const typeOfConstructorObject=typeof o.constructor==“函数”;设r;if(严格==真){r=(instanceOfObject | | typeOfObject)&&(constructorUndefined | | constructorObject);}其他{r=(constructorUndefined | | typeOfConstructorObject);}返回r;}// https://stackoverflow.com/a/42250981/860099函数N(x){return$.type(x)==“对象”;}// https://stackoverflow.com/a/34864175/860099函数O(x){if(Object.pr原型.toString.call(x)!=='[object对象]'){return false;}其他{var prototype=对象.getPrototypeOf(x);返回原型==null | |原型==Object.prototype;}}// https://stackoverflow.com/a/57863169/860099函数P(x){while(Object.product.toString.call(x)=='[Object Object]')if((x=Object.getPrototypeOf(x))==null)返回truereturn false}// https://stackoverflow.com/a/43289971/860099函数Q(x){尝试{开关(x.constructor){案例编号:case函数:大小写布尔值:case符号:案例日期:case字符串:大小写RegExp:return x.constructor==对象;case错误:case评估错误:大小写范围错误:案例引用错误:case语法错误:案例类型错误:大小写URI错误:return(对象==错误?错误:x.constructor)==对象;case数组:大小写Int8Array:大小写Uint8Array:case Uint8ClampedArray:大小写Int16Array:大小写Uint16Array:case Int32Array:大小写Uint32Array:case Float32阵列:case浮点64Array:return(对象==数组?数组:x.constructor)==对象;case对象:违约:return(对象==对象?对象:x.constructor)==对象;}}捕获(ex){return x==对象;}}// https://stackoverflow.com/a/52478680/860099函数R(x){return typeof x=='对象'&&x对象实例&&!(数组的x实例);}// https://stackoverflow.com/a/51458052/860099函数S(x){返回x!=null&&x.constructor?。name==“对象”}// https://stackoverflow.com/a/42250981/860099函数T(x){返回x?。构造函数?。toString().indexOf(“对象”)>-1;}// https://stackoverflow.com/a/43223661/860099函数U(x){返回x?。构造函数==对象;}// https://stackoverflow.com/a/46663081/860099函数V(x){返回x对象实例&&x.constructor==对象;}// -------------//测试// -------------console.log('列:1 2 3 4 5 6-7 8 9 10 11');[A、B、C、D、E、F、G、H、I、J、K、L、M、N、O、P、Q、R、S、T、U、V].map(f=>console.log(`${f.name}:${1*f(new Date()))}${1*f(/./)}${1*f({})}${1*f(Object.prototype)}{1*f(Object.create(null))}${1*f(()=>{})}-${1*f(“abc”)}美元{1*f(3)}$1 1*(true)}{1*(null)}$2 1*f(未定义)}`)))控制台日志(`列图例(测试用例):1:新日期()2: /./ (RegExp)3: {}4:对象.原型5:对象.create(null)6:()=>{}(函数)7:“abc”(字符串)8:3(数字)9:真(布尔值)10:空11:未定义排:1=是对象0=不是对象理论上,第1-6列应有1,第7-11列应有0`);<脚本src=“https://code.jquery.com/jquery-3.5.1.min.js"integrity=“sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphpj0=”crossoorigin=“匿名”></script><脚本src=“https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" 完整性=“sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==”crossoorigin=“匿名”></script>此shippet只显示性能测试中使用的函数,而不执行测试本身!
下面是铬的示例结果
只需检查对象或数组,无需额外的函数调用(速度)。同样张贴在这里。
isArray()
isArray = function(a) {
return (!!a) && (a.constructor === Array);
};
console.log(isArray( )); // false
console.log(isArray( null)); // false
console.log(isArray( true)); // false
console.log(isArray( 1)); // false
console.log(isArray( 'str')); // false
console.log(isArray( {})); // false
console.log(isArray(new Date)); // false
console.log(isArray( [])); // true
isLiteralObject()-注意:仅用于Object文本,因为它对自定义对象(如newDate或newYourCustomObject)返回false。
isLiteralObject = function(a) {
return (!!a) && (a.constructor === Object);
};
console.log(isLiteralObject( )); // false
console.log(isLiteralObject( null)); // false
console.log(isLiteralObject( true)); // false
console.log(isLiteralObject( 1)); // false
console.log(isLiteralObject( 'str')); // false
console.log(isLiteralObject( [])); // false
console.log(isLiteralObject(new Date)); // false
console.log(isLiteralObject( {})); // true
我从这个SO问题中找到了一种“新”方法来进行这种类型检查:为什么instanceof对某些文本返回false?
在此基础上,我创建了一个类型检查函数,如下所示:
function isVarTypeOf(_var, _type){
try {
return _var.constructor === _type;
} catch(ex) {
return false; //fallback for null or undefined
}
}
那么你可以这样做:
console.log(isVarTypeOf('asdf', String)); // returns true
console.log(isVarTypeOf(new String('asdf'), String)); // returns true
console.log(isVarTypeOf(123, String)); // returns false
console.log(isVarTypeOf(123, Number)); // returns true
console.log(isVarTypeOf(new Date(), String)); // returns false
console.log(isVarTypeOf(new Date(), Number)); // returns false
console.log(isVarTypeOf(new Date(), Date)); // returns true
console.log(isVarTypeOf([], Object)); // returns false
console.log(isVarTypeOf([], Array)); // returns true
console.log(isVarTypeOf({}, Object)); // returns true
console.log(isVarTypeOf({}, Array)); // returns false
console.log(isVarTypeOf(null, Object)); // returns false
console.log(isVarTypeOf(undefined, Object)); // returns false
console.log(isVarTypeOf(false, Boolean)); // returns true
这在Chrome 56、Firefox 52、Microsoft Edge 38、Internet Explorer 11和Opera 43上进行了测试
编辑:如果您还想检查变量是否为空或未定义,则可以使用以下方法:
function isVarTypeOf(_var, _type){
try {
return _var.constructor === _type;
} catch(ex) {
return _var == _type; //null and undefined are considered the same
// or you can use === if you want to differentiate them
}
}
var a = undefined, b = null;
console.log(isVarTypeOf(a, undefined)) // returns true
console.log(isVarTypeOf(b, undefined)) // returns true
console.log(isVarTypeOf(a, null)) // returns true
财务评论更新:接受挑战:D
如果要松散比较对象,可以尝试以下方法:
function isVarTypeOf(_var, _type, looseCompare){
if (!looseCompare){
try {
return _var.constructor === _type;
} catch(ex){
return _var == _type;
}
} else {
try{
switch(_var.constructor){
case Number:
case Function:
case Boolean:
case Symbol:
case Date:
case String:
case RegExp:
// add all standard objects you want to differentiate here
return _var.constructor === _type;
case Error:
case EvalError:
case RangeError:
case ReferenceError:
case SyntaxError:
case TypeError:
case URIError:
// all errors are considered the same when compared to generic Error
return (_type === Error ? Error : _var.constructor) === _type;
case Array:
case Int8Array:
case Uint8Array:
case Uint8ClampedArray:
case Int16Array:
case Uint16Array:
case Int32Array:
case Uint32Array:
case Float32Array:
case Float64Array:
// all types of array are considered the same when compared to generic Array
return (_type === Array ? Array : _var.constructor) === _type;
case Object:
default:
// the remaining are considered as custom class/object, so treat it as object when compared to generic Object
return (_type === Object ? Object : _var.constructor) === _type;
}
} catch(ex){
return _var == _type; //null and undefined are considered the same
// or you can use === if you want to differentiate them
}
}
}
这样,你就可以像finance的评论一样:
isVarTypeOf(new (function Foo(){}), Object); // returns false
isVarTypeOf(new (function Foo(){}), Object, true); // returns true
or
Foo = function(){};
Bar = function(){};
isVarTypeOf(new Foo(), Object); // returns false
isVarTypeOf(new Foo(), Object, true); // returns true
isVarTypeOf(new Bar(), Foo, true); // returns false
isVarTypeOf(new Bar(), Bar, true); // returns true
isVarTypeOf(new Bar(), Bar); // returns true
推荐文章
- 我如何使用Jest模拟JavaScript的“窗口”对象?
- 我如何等待一个承诺完成之前返回一个函数的变量?
- 在JavaScript中根据键值查找和删除数组中的对象
- 使嵌套JavaScript对象平放/不平放的最快方法
- 如何以及为什么'a'['toUpperCase']()在JavaScript工作?
- 有Grunt生成index.html不同的设置
- 文档之间的区别。addEventListener和window。addEventListener?
- 如何检查动态附加的事件监听器是否存在?
- 如何写setTimeout与参数Coffeescript
- 将JavaScript字符串中的多个空格替换为单个空格
- JavaScript: override alert()
- 重置setTimeout
- 如何确保<select>表单字段被禁用时提交?
- jQuery有不聚焦的方法吗?
- 反应钩子-正确的方式清除超时和间隔