2266

如何检查值是否是JavaScript中的对象?

10
  • 5
    变量就是变量。它可能指的是一个对象。此外,你可能想定义“对象”——正如答案和评论所示,有各种相互冲突的定义(例如,是否无效的是一个对象)。
    – 用户395760
    评论 2011年12月14日20:46
  • 9
    OP,IMO你应该接受@Daan的答案,因为这是最好的解决方案,并且应该列在其他答案的前面,所以它是第一个看到的。(没有冒犯其他也有好答案的人。)
    – 蒂芬
    评论 2015年11月17日21:11
  • 我个人认为,这实际上取决于你(寻找这个问题答案的人)对一个对象的看法,以及你为什么要检查它。如果你试图区分数组,这个问题会给出不同的答案(即对象)来自其他对象或试图将标量值与“向量”分离。以及是否为null(即对象(根据类型)或函数(即对象)是否应该被排除,这实际上取决于你为什么要检查它。这就是为什么有这么多答案,而且大多数答案在上下文中都是正确的。 评论 2017年2月8日11:52
  • 1
    如果你能从确切的意思是“是一个物体”。(或者,明确地说,你要寻找的答案之一是确定“是一个物体”的各种流行含义,然后区分它们。)没有这一点,每个人都在相互回避。 评论 2019年12月26日13:43
  • 1
    @tiffon如何在stackoverflow.com/a/52478680/1096194。我写这篇文章的时候,看到了许多投票率最高的答案中冗长的细节,我不知所措。我相信它值得更多的关注。 评论 2020年6月8日10:40

57个答案57

重置为默认值
2539

如果typeof x===“对象”,x个是对象(函数除外)或无效的。如果你愿意无效的、数组和要排除的函数,只需使其:

typeof x===“对象”&&!数组.isArray(x)&&x!==无效的
27
  • 81
    函数也是对象,应该包含在检查中。 评论 2012年12月21日18:25
  • 5
    在这种情况下您的变量!==无效的做得更好吗? 评论 2013年5月23日15:59
  • 12
    @没错Fred好像是这样typeof null==“对象”不会固定在欧洲标准6他们说:该提案已被拒绝。它是在V8中实现的,但它破坏了许多现有站点。本着OneJavaScript的精神,这是不可行的。 评论 2013年9月3日10:50
  • 17
    @Tresdin最好的办法是跑步Object.prototype.toString.call(yourVar),正在你的Var你需要检查什么。在阵列的情况下,Object.prototype.toString.call([1,2])收益[对象数组] 评论 2016年2月25日9:48
  • 27
    被否决是因为数组也被视为对象,所以您还应该检查数组.isArray(yourVariable). 评论 2017年11月29日22:34
967

更新:

这个答案是不完整的,会产生误导性的结果例如,无效的也被视为类型对象在JavaScript中,更不用说其他一些边缘情况了。遵循以下建议并继续“投票最多(而且正确!)的答案”:

yourVariable的类型===“对象”&&yourVaiable!==无效的

原答覆:

尝试使用类型(var)和/或某物的var实例.

编辑:这个答案给出了如何检查变量属性的思路,但它是一个防弹配方(毕竟根本没有配方!),用于检查它是否是一个物体,离它很远。由于人们倾向于从这里寻找要复制的东西,而不做任何研究,我强烈建议他们转向另一个投票最多(而且正确!)的答案。

29
  • 149
    这个答案不正确。类型为null返回“object”,这不是一个对象,并且运算符不适用于使用创建的对象Object.create(空).
    – 尼古拉
    评论 2014年4月8日21时12分
  • null类型...对象! 评论 2014年9月15日19:14
  • 21
    数组也将作为“对象”返回,如下所示:someArray对象实例//truetypeof someArray===“对象”//true。关于:Object.prototype.toString.call(someObject)===“[对象对象]”,或“[对象数组]”如果你想检测阵列? 评论 2015年6月19日14:52
  • 9
    @乔纳森,有更好的理由否决我的回答,你碰巧有军事背景吗 评论 2015年9月8日11:54
  • 10
    这不应该是公认的答案。除了乔纳森提出的风格问题外,这完全是错误的,没有提到例如@matt-fenwick的回答中非常重要的微妙之处。 评论 2016年1月18日20:27
630

让我们在Javascript中定义“对象”.根据MDN文档,每个值都是对象或基本体:

基元,基元值

不是对象且没有任何方法的数据。JavaScript有7种基本数据类型:string、number、bigint、boolean、undefined、symbol和null。

什么是原语?

  • “abc”
  • 真的
  • 无效的
  • 未定义

什么是对象(即非基本体)?

  • 对象.原型
  • 一切都是从对象.原型
    • 函数.原型
      • 对象
      • 功能
      • 函数C(){}--用户定义函数
    • C.原型--用户定义函数的原型属性:这是 C类s原型
      • 新C()--“新建”-使用用户定义的函数
    • 数学
    • 阵列原型
      • 阵列
    • {“a”:1,“b”:2}--使用文字符号创建的对象
    • 新编号(3)--基本体周围的包装
    • ...还有很多其他事情...
  • Object.create(空)
  • 一切都源于Object.create(null)

如何检查值是否为对象

运算符它本身不会起作用,因为它遗漏了两个案例:

//oops:isObject(Object.prototype)->false//oops:isObject(Object.create(null))->false函数isObject(val){return val对象实例;}

typeof x===“对象”由于假阳性,无法工作(无效的)和假阴性(函数):

//oops:isObject(Object)->false函数isObject(val){return(类型val===“对象”);}

对象.原型.to字符串.call不会起作用,因为所有原语都是误报:

>Object.prototype.toString.call(3)“[对象编号]”>Object.prototype.toString.call(新编号(3))“[对象编号]”

所以我使用:

函数isObject(val){if(val===null){return false;}return((类型为val==='函数')||(类型为val==='对象'));}

@Daan的回答似乎也有效:

函数isObject(obj){return obj===对象(obj);}

因为,根据MDN文档:

Object构造函数为给定值创建对象包装器。如果值为null或未定义,它将创建并返回一个空对象,否则,它将返回一个与给定值对应的类型的对象。如果该值已经是一个对象,它将返回该值。


第三种似乎有效的方法(不确定是否为100%)是使用对象.get原型哪一个引发异常如果其参数不是对象:

//这5个示例抛出异常Object.getPrototypeOf(空)Object.getPrototypeOf(未定义)Object.getPrototypeOf(3)Object.getPrototypeOf('abc')Object.getPrototypeOf(true)//这5个示例没有抛出异常Object.getPrototypeOf(对象)Object.getPrototypeOf(Object.protype)Object.getPrototypeOf(Object.create(null))Object.getPrototypeOf([])Object.getPrototypeOf({})
12
  • 48
    obj===对象(obj)收益真的用于数组。 评论 2016年2月15日17:10
  • 6
    var x=[];console.log(x===对象(x));//返回true
    – 照明器
    评论 2016年4月8日7:51
  • 23
    @照明器阵列Javascript中的对象,正如我在回答中提到的。 评论 2016年4月8日14:20
  • 1
    获取原型不起作用,例如,使用已撤销的代理,这些代理是对象但抛出。 评论 2016年8月28日1:03
  • 6
    为什么不呢?({}).toString.apply(obj)===“[对象对象]”这就区分了数组和非数组对象 评论 2018年11月6日22:09
370
+100

下核.js提供了以下方法来确定某物是否真的是对象:

_.isObject=函数(obj){return obj===对象(obj);};

更新

由于V8之前的一个错误和微小的微速度优化,该方法看起来如下underscore.js 1.7.0(下核.js 1.7.0)(2014年8月):

_.isObject=函数(obj){var类型=对象类型;return type===“函数”||type==='对象'&&!!对象;};
14
  • 70
    在javascript中,数组也是一个对象,因此大多数时候您都希望排除数组:return obj===对象(obj)&&Object.prototype.toString.call(obj,obj)!=='[对象数组]'
    – 大安
    评论 2013年7月12日8:57
  • 28
    为什么要排除数组?它们是成熟的物体。
    – 尼古拉
    评论 2014年4月8日21:17
  • 92
    因为大多数时候您都想将{}和[]区分开来,例如作为函数中的输入
    – 大安
    评论 2014年4月9日9:39
  • 7
    @尼克莱。。以及用于迭代嵌套对象。 评论 2014年5月22日1:18
  • 7
    回答得很好。把手无效的也是。应该是公认的答案。
    – 蒂芬
    评论 2015年11月17日20:59
232

Object.prototype.toString.call(myVar)将返回:

  • “[对象对象]”如果myVar是对象
  • “[对象数组]”如果myVar是数组
  • 等。

有关这方面的更多信息,以及为什么它是typeof的好替代品,看看这篇文章.

11
  • 19
    我最近才知道typeof[]===“对象”-->真的。这就是你需要的方法。
    – 乔德姆
    评论 2013年8月11日5:29
  • 5
    @克利斯朵夫没有区分原语和物体.Object.prototype.toString.call(3)->“[对象编号]”.Object.prototype.toString.call(新编号(3))->“[对象编号]" 评论 2014年3月18日17:25
  • 9
    @MattFenwick我不认为这是OP想要识别的那种“物体” 评论 2014年3月19日5:21
  • @克利斯朵夫,你为什么这么认为?IMHO,在OP没有给出“对象”的任何其他定义的情况下,我认为最合理的做法是使用ECS规范中一致使用的定义。 评论 2014年3月19日11:36
  • getType=function(obj){return Object.prototype.toString.call(obj).match(/\[对象(\w+)\]/)[1];}; 评论 2014年11月17日22:08
214

用于简单检查对象阵列无需额外的函数调用(速度)。同样发布了在这里.

isArray()

isArray=函数(a){return(!!a)&&(a.constructor===数组);};console.log(isArray());//console.log(isArray(null));//console.log(isArray(true));//console.log(isArray(1));//console.log(isArray('str'));//console.log(isArray({}));//console.log(isArray(new Date));//console.log(isArray([]));//真的

isLiteral对象()-注:用于对象只返回文字对于自定义对象,如新日期新建YourCustomObject.

isLiteralObject=函数(a){return(!!a)&&(a.constructor===对象);};console.log(isLiteralObject());//console.log(isLiteralObject(null));//console.log(isLiteralObject(true));//console.log(isLiteralObject(1));//console.log(isLiteralObject('str'));//console.log(isLiteralObject([]));//console.log(isLiteralObject(新日期));//console.log(isLiteralObject({}));//真的
19
  • 4
    @祖帕:什么!!a是吗?
    – 用户1094081
    评论 2015年4月23日10:59
  • 9
    @3000好吧,如果我们省略(!!a)部分,它就会崩溃,因为null和undefined没有构造函数。(!!a)过滤掉它们。这回答了你的问题吗?
    – 祖帕
    评论 2015年4月27日15:26
  • @zupa@3000布尔值(a)更长,但更直观。只是不要使用新布尔值(a): (原因如下)! 评论 2015年8月20日13:32
  • 30
    出乎意料的是,到目前为止,最好的答案都在下面。这基本上回答了这个问题——这会在JSON中表示为以{字符。对于阵列情况,只要不需要支持IE<9,就可以使用数组.isArray()确定某个东西是否是数组。它通过了您提供的所有测试用例。
    – 基普
    评论 2016年3月10日14:56
  • @BradKent没有双重否定!! isObject(空)会回来的无效的而不是
    – AKG公司
    评论 2019年8月13日22:43
106

我喜欢简单地说:

函数isObject(item){return(typeof item===“object”&&!Array.isArray(item)&&item!==空);}

如果该项是JS对象,并且不是JS数组,也不是无效的……如果这三个都证明是真的,请返回真的。如果三个条件中的任何一个失败&&测试将短路将返回。这个无效的如果需要,可以省略测试(取决于您的使用方式无效的).

文件编号:

http://devdocs.io/javascript/operators/typeof

http://devdocs.io/javascript/global_objects/object

http://devdocs.io/javascript/global_objects/array/isaray

http://devdocs.io/javascript/global_objects/null

11
  • 4
    那么console.log(isObject(new Date()))呢?为什么日期应该是对象而不是数组? 评论 2015年6月28日19:21
  • 8
    @马赫因为新日期()返回一个对象。数组是从逻辑的角度来看的,而不是一个对象,尽管JavaScript会这样处理和报告它们。然而,在实践中,看到他们平等是无益的,因为他们并非如此。对象没有长度属性,并且它没有像push()这样的方法。有时你可能想给一个函数重载参数,在这里你需要区分数组或对象,特别是当其他参数取决于给定的参数时。 评论 2016年8月5日22:10
  • 2
    @StanE阵列绝对是对象。不确定为什么您认为对象不能具有长度属性或类似的方法,Object.create(Array.prototype)是一个具有这些属性的非数组对象的简单反例。数组的特殊之处在于,它们是带有自定义[[DefineOwnProperty]]基本内部方法的外来对象,但它们仍然是对象。 评论 2016年8月28日19:50
  • 5
    @Oriol我既没有写数组不是对象,也没有写对象不能有长度属性(我的意思是对象文字没有长度属性)。我写道,数组不是来自符合逻辑的观点。我说的是程序逻辑。有时有必要检查数组是否是“真实”数组,而绝对不是“真实”对象。就是这样数组.isArray()是的。假设您有一个接受对象或对象数组的函数。检查特殊属性或方法是一种肮脏的解决方案。土生土长的方式总是更好。 评论 2016年8月29日21:50
  • 2
    null类型“对象”,不是“未定义”.
    – 2540625
    评论 2016年10月1日21:05
102

使用函数阵列.isArray:

函数isObject(o){返回o!==null&&typeof o===“对象”&&Array.isArray(o)===false;}

无功能阵列.isArray:

只是奇怪有多少人支持错误的答案😮
仅限1个答案通过了我的测试!!!在这里,我创建了我的简化版本:

函数isObject(o){return o对象实例&&o.constructor===对象;}

对我来说,它清晰而简单,而且很有效!这里是我的测试:

console.log(isObject({}));//将返回:trueconsole.log(isObject([]));//将返回:falseconsole.log(isObject(null));//将返回:falseconsole.log(isObject(/.*/));//将返回:falseconsole.log(isObject(函数(){}));//将返回:false

再一次:并非所有答案都通过了测试!!!🙈


如果您需要验证对象特定类的实例您必须使用特定类检查构造函数,如:

函数isDate(o){return o instanceof Object&&o.constructor===日期;}

简单测试:

var d=新日期();console.log(isObject(d));//将返回:falseconsole.log(isDate(d));//将返回:true

因此,您将拥有严格而健壮的代码!


如果您不会创建以下功能isDate(是日期),is错误,isRegExp公司等,您可以考虑使用此通用函数的选项:

函数isObject(o){return o instanceof Object&&typeof o.constructor===“函数”;}

它不能正确地用于前面提到的所有测试用例,但对于所有对象(普通的或构造的)来说已经足够了。


is对象在发生以下情况时不起作用Object.create(空)因为内部实施对象创建这是解释在这里但你可以使用is对象在更复杂的实现中:

函数isObject(o,strict=true){if(o===null||o===未定义){返回false;}const instanceOfObject=o对象实例;const typeOfObject=类型o===“对象”;const constructorUndefined=o.constructor===未定义;const constructorObject=o.constructor===对象;const typeOfConstructorObject=o.constructor类型===“函数”;设r;if(严格===真){r=(instanceOfObject||typeOfObject)&&(constructorUndefined||constructor对象);}其他{r=(constructorUndefined||typeOfConstructorObject);}返回r;};

已经创建了npm上的包v1基于此实现!它适用于所有先前描述的测试用例!🙂

7
  • 1
    最佳答案!为提到的许多案例工作在这里 评论 2017年10月20日8:57
  • 1
    因为这对isObject(myDateObject)返回false,所以这不是问题的答案。它不知道变量是否是对象,只知道它是否是特定类的对象。这里的问题是对于任何对象都返回true的泛型函数。 评论 2018年1月13日19:09
  • @Yetanotherjosh这确实是个答案🤓 你提到了答案中描述的案例,以及要点-你必须使用isDate(是日期)为您的DateObject编写健壮的代码,否则您将变得脆弱is对象方法。
    – cn0047号
    评论 2018年1月19日17:03
  • 1
    @Vladimir Kovpak使用日期在我的评论中没有选择,因为是的,答案确实讨论了日期.但是日期只是无限可能的类之一,这一点适用于任何其他类。例子:类Foo(){};var x=新Foo();是对象(x)收益。我不知道OP的具体用例是什么,但很容易想到必须了解的场景所有可能的类和检查专门针对他们中的每一个人是不可行的。 评论 2018年1月19日21:09
  • 1
    使用运算符不适用于从创建的对象Object.create(空). 评论 2018年2月11日5:19
96

哦,我的上帝!我认为这可能比以往更短,让我们看看:

短代码和最终代码

函数isObject(obj){返回对象!=null&&obj.constructor.name===“对象”}console.log(isObject({}))//返回trueconsole.log(isObject([]))//返回falseconsole.log(isObject(null))//返回false

解释

退货类型

JavaScript对象的类型(包括无效的)收益“对象”

console.log(typeofnull,typeof[],typeof{})

检查他们的施工人员

检查他们的建造师属性返回函数及其名称。

console.log(({}).constructor)//返回名为“Object”的函数console.log(([]).constructor)//返回一个名为“Array”的函数console.log((null).constructor)//抛出错误,因为null实际上没有属性

函数名称简介

功能名称返回函数的只读名称或“匿名”用于闭合。

console.log(({}).constructor.name)//返回“Object”console.log(([]).constructor.name)//返回“Array”console.log((null).constructor.name)//抛出错误,因为null实际上没有属性

注: 截至2018年,Function.name可能无法在中使用工业工程

  • 7
    我真的很喜欢这个,简短而中肯。据我所见,它只在一件事上失败了。如果对象=Object.create(空)还有你为什么要这么做。。。? 评论 2020年2月17日20:01
  • 如果您愿意,可以排除这种罕见的情况:返回对象!=null&&obj.constructor&&obj.construtor.name===“对象”条件“obj.constructor”返回false,因为Object.create(null)创建的对象没有属性,甚至没有属性__proto__或.constructor。 评论 2021年11月8日15:57
  • 根据您的回答,我在NodeJS中的最后一个(ES11)助手是:const is对象=(obj)=>(obj??false)?。构造函数?。name===“对象”;谢谢您!
    – 赛吉奥
    评论 2021年12月15日10:53
35

试试这个

if(objectName对象实例){警报(“物体”);}其他{alert(“非对象”);}
4
  • 5
    这遗漏了两种情况:Object.原型实例Object->false。Object.create(null)instanceof对象->false。 评论 2014年3月18日14:45
  • 1
    日期呢?new Date()对象实例=>真
    – 毛龙85
    评论 2016年10月9日17:04
  • 2
    这段代码假设数组是对象。 评论 2022年3月31日7:58
  • 1
    那是因为两者都是日期s和数组物体。 评论 2023年5月4日22:28
31

好吧,在回答你的问题之前,让我们先给你这个概念,在JavaScript中,函数是Object,也有null、Object、Arrays甚至Date,所以你可以看到像typeofobj===“object”这样的简单方法,所以上面提到的所有内容都将返回true,但可以通过编写函数或使用JavaScript框架进行检查,好的:

现在,假设您有一个真正的对象(不是null或函数或数组):

变量obj={obj1:“obj1”,obj2:“obj 2”};

纯JavaScript:

//这就是如何在角度框架中进行检查函数isObject(obj){返回对象!==null&&typeof obj===“对象”;}

//确保第二个对象大写函数isObject(obj){return Object.prototype.toString.call(obj)===“[对象对象]”;}

函数isObject(obj){return obj.constructor.toString().indexOf(“Object”)>-1;}

函数isObject(obj){return obj instanceof Object;}

您可以简单地在代码中使用上述函数之一,方法是调用它们,如果它是一个对象,它将返回true:

是对象(obj);

如果您使用的是JavaScript框架,他们通常会为您准备这些功能,以下是其中的一些功能:

jQuery:

//如果是实object,则返回“object”;jQuery.type(obj);

角度:

角度.is对象(obj);

下划线和Lodash:

//(注意:在Undercore和Lodash中,函数和数组也返回true,但不返回null)_.is对象(obj);
2
  • 您还需要检查它是否不是数组。所以函数isObject(obj){return obj!==null&&typeof obj===“object”&&!Array.isArray(obj);} 评论 2017年4月3日19:51
  • 我同意你的观点,但正如你在注释中看到的,这是如何在angularJ中完成的,我在函数前面的注释中提到过,他们将数组作为一个对象。。。查看此处了解更多信息:docs.angularjs.org/api/ng/function/angular.is对象 评论 2017年4月4日0:50
30

这取决于你所说的“是一个物体”是什么意思。如果你想要的不是原始的也就是说,您可以对其设置新属性,这应该可以做到:

函数isAnyObject(值){返回值!=null&&(typeof value===“object”||typeof value===“function”);}

它不包括原语(普通数字/NaN公司/无穷,普通字符串,符号,真的/,未定义无效的)但对于其他一切(包括编号,布尔值字符串对象)。注意,JS没有定义什么“主机”对象,例如窗口慰问,与一起使用时应返回类型,所以像这样的支票很难盖住这些。

如果你想知道某个东西是否是一个“普通”对象,即它是作为文字创建的{}或使用Object.create(空),您可以这样做:

函数isPlainObject(值){if(Object.prototype.toString.call(value)!=='[object对象]'){返回false;}其他{var prototype=Object.getPrototypeOf(值);return prototype===null||prototype===Object.prototype;}}

2018年编辑:因为符号.to字符串标记现在允许自定义Object.prototype.toString.call(…),的isPlain对象上面的函数可能返回在某些情况下,甚至当对象以文字形式开始其生命时。可以说,按照惯例,带有自定义字符串标记的对象不再是纯对象,但这进一步模糊了Javascript中纯对象的定义。

2
  • 为什么typeof===“function”被视为对象?函数不是对象,不是吗?“new myFunc()”将成为一个对象,是的,但它是一个普通函数吗? 评论 2016年8月5日21:59
  • 不,在Javascript中,每个函数都是一个对象,无论它是如何创建的。您可以设置它们的属性(除非它们被冻结),它们是对象实例,两个相同的函数文字不是严格相等的,它们是通过引用传递的,等等。 评论 2016年10月29日10:38
27

我的上帝,其他答案太混乱了。

简短回答

typeof anyVar==“object”&&anyVar对象实例&&!(数组的anyVar实例)

要测试这一点,只需在chrome控制台中运行以下语句。

案例1。

变量anyVar={};typeof anyVar==“object”&&anyVar对象实例&&!(anyVar数组实例)//true

案例2。

任意变量=[];typeof anyVar==“object”&&anyVar对象实例&&!(anyVar数组实例)//false

案例3。

anyVar=空;typeof anyVar==“object”&&anyVar对象实例&&!(数组的anyVar实例);//

解释

可以。让我们把它分解

typeof anyVar==“对象”三位候选人回答为“真”-[]、{}和null,

对象的anyVar实例把这些候选人缩小到两人-[], {}

!(数组的anyVar实例)缩小到只有一个-{}

请滚圆!

通过此操作,您可能已经学会了如何在Javascript中检查数组。

  • 值得注意的是,这也会返回(根据需要)何时任意Var是一个函数。 评论 2019年2月12日15:34
  • 答案很好@HalfWebDev,但为了满足Jamie Birch所评论的功能,我们可以使用这种类型的anyVar==“object”&&anyVar实例object&&!(anyVar数组实例)&&typeof anyVar!=='函数' 评论 2021年5月2日15:35
  • 1
    new Date()将在此处返回true。可以修复!(anyVar日期实例) 评论 2022年12月26日23:15
22

下面是可选链接的答案,可能是最小的是对象此问题的函数。

常量isObj=o=>o?。constructor===对象;//这是真的控制台.log(isObj({}));//反对!//这些错误console.log(isObj(0));//console.log(isObj([]));//阵列console.log(isObj('lo'));//一串console.log(isObj(null));//无效的console.log(isObj(未定义));//未定义控制台.log(isObj(()=>{}));//功能console.log(isObj(Object));//

7
  • 1
    新错误()在你的函数中是错误的。 评论 2020年5月15日1:03
  • @蒂尼罗伊不是应该这样吗?错误实例不是对象。如果我做错了什么,请告诉我。:) 评论 2020年5月16日17:43
  • 如果您的意图是排除从Object继承的实例,那么您是对的,但我将它们视为对象。它们具有对象的所有属性。 评论 2020年5月17日21:55
  • 我相信这就是问题所在。否则,基本上所有内容都继承自Object。 评论 2020年5月18日8:48
  • 什么是'?“标志意味着什么? 评论 2020年9月12日14:26
21

检查值类型的最合理方法似乎是类型操作员。唯一的问题是它破得很厉害:

  • 它会返回“对象”对于无效的,属于Null类型。
  • 它会返回“功能”对于属于Object类型的可调用对象。
  • 它可以为非标准的不可调用对象返回(几乎)它想要的任何内容。例如,IE似乎喜欢“未知”。唯一禁止的结果是“功能”和基元类型。

类型(共种)仅对非-无效的基本体。因此,检查值是否为对象的方法是确保类型与基元不对应,并且对象不是无效的然而,问题是未来的标准可能会引入新的基元类型,而我们的代码会将其视为对象。新类型并不经常出现,但例如ECMAScript 6引入了Symbol类型。

因此类型,我只推荐结果根据值是否为对象而变化的方法。以下内容旨在成为

测试值是否属于Object类型的正确方法的全面列表,但并不详尽。

  • 对象建造师

    这个对象构造函数将传递的参数强制为对象。如果它已经是一个对象,则返回相同的对象。

    因此,可以使用它将值强制为对象,并将该对象与原始值进行严格比较。

    以下函数需要ECMAScript 3,它引入了===:

    函数isObject(value){/*需要ECMAScript 3或更高版本*/return Object(value)===value;}

    我喜欢这种方法,因为它简单且自我描述,类似的检查也适用于布尔值、数字和字符串。然而,要知道它依赖于全球对象没有被遮蔽或改变。

  • 建造师

    实例化构造函数时,它可以返回与刚创建的实例不同的值。但该值将被忽略,除非它是一个对象。

    以下函数需要ECMAScript 3,它允许构造函数返回非对象。在引发错误的ECMAScript 3之前,但是尝试当时还没有声明。

    函数isObject(value){/*需要ECMAScript 3或更高版本*/return new function(){return value;}()===value;}

    虽然与前一个示例相比有点简单,但此示例不依赖任何全局属性,因此可能是最安全的。

  • 价值

    旧的ECMAScript规范要求值作为对象。引入ECMAScript 3功能.原型.call,它允许使用任意值,但强制为对象。

    ECMAScript 5引入了一个严格的模式来消除这种行为,但在草率模式下,我们仍然可以(但可以说不应该)依赖它。

    function isObject(value){/*在slopy模式下需要ECMAScript 3或更高版本*/return function(){return this==value;}.call(value);}
  • [[原型]]

    所有普通对象都有一个名为[[Prototype]]的内部插槽,其值决定了它从哪个其他对象继承。该值只能是对象或无效的。因此,您可以尝试创建从所需值继承的对象,并检查它是否有效。

    两者都有对象.创建对象.get原型需要ECMAScript 5。

    函数isObject(value){/*需要ECMAScript 5或更高版本*/尝试{Object.create(值);返回值!==无效的;}捕获(错误){返回false;}}
    函数isObject(value){/*需要ECMAScript 5或更高版本*/函数构造函数(){}Constructor.protype=值;return Object.getPrototypeOf(new Constructor())===值;}
  • 一些新的ECMAScript 6方式

    ECMAScript 6引入了一些新的间接方法来检查值是否为对象。它们使用前面看到的方法将值传递给一些需要对象的代码,这些对象包装在尝试语句捕获错误。一些隐藏的例子,不值得评论

    函数isObject(value){/*需要ECMAScript 6或更高版本*/尝试{Object.setPrototypeOf({},值);返回值!==无效的;}捕获(错误){返回false;}}

    函数isObject(value){/*需要ECMAScript 6或更高版本*/尝试{新的WeakSet([值]);返回true;}捕获(错误){返回false;}}


注意:我故意跳过了一些方法,比如Object.getPrototypeOf(值)(ES5)和反射方法(ES6),因为它们称为可能会做出令人讨厌的事情的基本内部方法,例如,如果价值是代理。出于安全考虑,我的示例仅供参考价值没有直接访问它。

5
  • 2
    “只有我和Daan的答案是完全正确的。”考虑到我,这有点冒昧完全不同意用你的前两句话。 评论 2016年9月2日16:31
  • 1
    @zzzzBov好吧,我看了所有的答案,他们不保证总是返回正确的答案,除了我和Daan的。我可以为他们中的大多数给出可重复的反例。其他人建议检查typeof是否返回“function”或“object”,但正如我解释的那样,规范允许对某些对象使用其他结果。Matt Fenwick的答案包含与Daan相同的正确答案,但也包含不正确的答案。 评论 2016年9月2日16:59
  • 1
    我不同意你的回答“完全正确”的前提,认为其他人“不能确保总是返回正确的答案”并没有以任何方式反驳我的立场。此外,这个问题并没有提出任何关于什么输入应该产生什么输出的主张。 评论 2016年9月2日17:04
  • 2
    @zzzzBov该问题询问如何检查某物是否为对象。ECMAScript定义了对象是什么,所以我使用了这个定义。我看不出任何其他合理的解释。在某些情况下,做其他事情的答案(例如排除数组)可能很有用,但它们不会检查某个对象是否为对象。 评论 2016年9月2日17:28
  • @Oriol也许你可以回答这个问题为什么JavaScript中没有内置方法来检查对象是否为普通对象?? 评论 2016年11月7日2:35
19

随时可用的检查功能

函数isObject(o){返回null!=o和&类型o===“对象”&&Object.prototype.toString.call(o)===“[对象对象]”;}函数isDerivedObject(o){返回!是对象(o)&&空!=o和&(typeof o===“对象”|| typeof o===“函数”)&&/^\[对象/.test(object.prototype.toString.call(o));}//松散等式运算符(==)专门用于检查//对于未定义的//还要注意,即使null也是isDerivedObject中的一个对象//函数,我们跳过它并总是为null返回false

解释

  • 在Javascript中,无效的,对象,阵列,日期功能s都是对象。虽然,无效的有点做作。因此,最好检查无效的首先,检测它不为空。

  • 正在检查typeof o===“对象”保证o(o)是一个对象。如果没有这张支票,对象.原型.to字符串这是毫无意义的,因为它会为任何事物返回对象,即使是未定义无效的! 例如:toString(未定义)收益[对象未定义]!

    之后typeof o===“对象”check,toString.call(o)是检查o(o)是一个对象,类似于阵列,日期功能.

  • 是派生对象函数,它检查o(o)是一个函数。因为函数也是一个对象,这就是它存在的原因。如果它没有这样做,函数将返回false。例子:是派生对象(函数(){})会回来的但现在它又回来了真的.

  • 人们总是可以改变对象的定义。因此,可以相应地更改这些函数。


测验

函数isObject(o){返回null!=o&&类型o===“对象”&&Object.prototype.toString.call(o)===“[对象对象]”;}函数isDerivedObject(o){返回!is对象(o)&&空!=o和&(typeof o===“对象”|| typeof o===“函数”)&&/^\[对象/.test(object.prototype.toString.call(o));}//测试//null是一个对象吗?控制台.log('是否为null对象?',isObject(空));控制台.log(“null是派生对象吗?”,isDerivedObject(空));//1234是一个对象吗?控制台.log('1234是对象吗?',是对象(1234));控制台日志('1234是派生对象吗?',是派生对象(1234));//新数字(1234)是对象吗?控制台.log('新编号(1234)是对象吗?',isObject(新编号(1234)));控制台.log('新编号(1234)是派生对象吗?',是派生对象(1234));//函数对象是对象吗?控制台.log('(new(function(){}))是对象吗?',isObject((新(函数(){})));控制台.log('(new(function(){}))是派生对象吗?',isObject((new(function(){})));//{}是对象吗?控制台.log(“{}是对象吗?”,是对象({}));控制台日志(“{}是派生对象吗?”,是派生对象({}));//数组是对象吗?控制台.log('数组是对象吗?',是对象([]))控制台.log(“Array是派生对象吗?”,是派生对象([]))//Date是对象吗?控制台.log('日期是对象吗?',isObject(新日期()));控制台.log(“Date是派生对象吗?”,isDerivedObject(new Date()));//函数是一个对象吗?控制台.log('函数是对象吗?',isObject(函数(){}));控制台.log('函数是派生对象吗?',是派生对象(函数(){}));

1
  • 你好!很棒的帖子,但有一个小的拼写错误,即使它产生了正确的结果:console.log(“(new(function(){}))是派生对象吗?”,isObject((新(函数(){}))); 评论 2020年10月7日10:48
18

有点晚了。。。对于“普通对象”(我的意思是,像{'x':5,'y':7}),我有一个小片段:

函数isPlainObject(o){return(o===null||Array.isArray(o)||typeof o=='函数'||o.constructor===日期)?:(类型o==“对象”);}

它生成下一个输出:

console.debug(isPlainObject(isPlain Object))//函数,falseconsole.debug(isPlainObject({'x':6,'y':16}))//文字对象,trueconsole.debug(isPlainObject(5))//数字,假console.debug(isPlainObject(未定义))//未定义,错误console.debug(isPlainObject(null))//空,假console.debug(isPlainObject('a'))//字符串,falseconsole.debug(isPlainObject([]))//数组?,console.debug(isPlainObject(true))//布尔,假console.debug(isPlainObject(false))//布尔,假

它总是适用于我。只有当“o”的类型是“object”,而不是null、数组或函数时,If才会返回“true”。:)

1
  • 如前所述,如果是Date对象,您的方法将失败。 评论 2017年3月20日20:49
14

如果您想检查原型对于对象完全来自对象.过滤掉字符串,编号,阵列,论据等。

函数isObject(n){return Object.prototype.toString.call(n)===“[对象对象]”;}

或作为单表达式箭头函数(ES6+)

const isObject=n=>Object.prototype.toString.call(n)===“[对象对象]”
2
  • 1
    这是最好的方法,但我会在第二条线上更容易:return Object.prototype.toString.call(n)===“[对象对象]”
    – 网状物
    评论 2018年6月10日4:19
  • 1
    您还可以删除无效的检查,因为Object.prototype.toString.call(null)===“[Object null]” 评论 2019年11月6日0:02
13
变量a=[1]//“对象”的类型Object的一个实例//true数组的一个实例//true变量b={a:1}b对象实例//trueb数组实例//falsevar c=空c对象实例//falsec数组实例//false

我被要求提供更多细节。检查变量是否为对象的最干净、最容易理解的方法是myVar的类型。它返回一个带有类型的字符串(例如。“对象”,“未定义”).

不幸的是,Array和null也有一个类型对象。要仅获取真实对象,需要使用检查继承链运算符操作员。它将消除null,但Array在继承链中有Object。

所以解决方案是:

if(myVar instanceof Object&&!(myVar-instanceof Array)){//对象代码}
2
  • /./ instanceof Object//真
    – 伊卡车
    评论 2017年6月17日8:14
  • 如果使用final soution,函数将被视为对象
    – LKB公司
    评论 2021年11月10日0:57
12

洛达什有isPlain对象,这可能是许多来到本页的人所寻找的。当给定函数或数组时,它返回false。

1
  • 很 完美!我知道_.is对象这与JS认为的对象相匹配。但我通常需要区分对象文字和数组,这正是_.isPlain对象让我来吧。
    – 石灰
    评论 2014年12月16日11:11
12

这个兰达函数库有一个很好的检测JavaScript类型的功能。

解释全功能:

功能类型(val){返回val===空?'空':val===未定义?'“未定义”:Object.prototype.toString.call(val).slice(8,-1);}

当我意识到这个解决方案是多么简单和美丽时,我忍不住笑了。

Ramda的用法示例文档:

R.type({});//=>“对象”R型(1);//=>“数字”R.type(错误);//=>“布尔型”R.type(s’);//=>“字符串”R.type(空);//=>“空”R型([]);//=>“数组”R型(/[A-z]/);//=>“RegExp”R.type(()=>{});//=>“功能”R.type(未定义);//=>“未定义”
11

性能

今天2020.09.26,我在Chrome v85、Safari v13.1.2和Firefox v80上对MacO HighSierra 10.13.6进行了测试,以获得选定的解决方案。

结果

  • 在所有情况下,解决方案C和H在所有浏览器上都是快速/最快的
  • 在所有情况下,解决方案D和G在所有浏览器上都是最慢/最慢的

在此处输入图像描述

细节

我为解决方案执行了3个测试用例A类 B类 C类 D类 E类 F类 G公司 H(H) J型 K(K) L(左) M(M) N个 O(运行) P(P) R(右) S公司 T型 U型 V(V)

下面的代码片段显示了解决方案之间的差异。解决方案A-G为以下描述的所选案例提供了适当的答案马特·芬威克

// https://stackoverflow.com/a/14706877/860099函数A(x){return x===对象(x);};// https://stackoverflow.com/a/42250981/860099函数B(x){返回_.isObject(x);}// https://stackoverflow.com/a/34864175/860099函数C(x){返回x!=null&&(typeof x===‘object’||typeof x===‘function’);}// https://stackoverflow.com/a/39187058/860099函数D(x){return new function(){return x;}()===x;}// https://stackoverflow.com/a/39187058/860099函数E(x){return function(){return this===x;}.call(x);}// https://stackoverflow.com/a/39187058/860099函数F(x){/*需要ECMAScript 5或更高版本*/尝试{Object.create(x);返回x!==无效的;}捕获(错误){返回false;}}// https://stackoverflow.com/a/39187058/860099函数G(x){/*需要ECMAScript 5或更高版本*/函数构造函数(){}构造函数原型=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]===“{”:假;}// https://stackoverflow.com/a/13356338/860099函数L(x){return Object.prototype.toString.call(x)===“[对象对象]”;};// https://stackoverflow.com/a/46663081/860099函数M(o,strict=true){if(o===null||o===未定义){返回false;}const instanceOfObject=o对象实例;const typeOfObject=类型o===“对象”;const constructorUndefined=o.constructor===未定义;const constructorObject=o.constructor===对象;const typeOfConstructorObject=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.prototype.toString.call(x)!=='[对象对象]'){返回false;}其他{var原型=Object.getPrototypeOf(x);return prototype===null||prototype===Object.prototype;}}// https://stackoverflow.com/a/57863169/860099函数P(x){while(Object.prototype.toString.call(x)===“[对象对象]”)if((x=Object.getPrototypeOf(x))===null)返回true返回false}// https://stackoverflow.com/a/43289971/860099函数Q(x){尝试{开关(x.constructor){案例编号:case函数:case布尔值:外壳符号:案例日期:case字符串:案例RegExp:return x.constructor===对象;case错误:案例评估错误:案例范围错误:案例引用错误:case语法错误:案例类型错误:案例URI错误:return(Object===错误?错误:x.constructor)===对象;case数组:case Int8Array(大小写Int8Array):case Uint8Array:case Uint8ClampedArray:案例Int16Array:案例Uint16Array:案例Int32Array:案例Uint32Array:案例Float32Array:案例Float64Array:return(Object===数组?数组:x.constructor)===对象;case对象:违约:return(Object===Object?Object:x.constructor)===对象;}}捕获(ex){return x==对象;}}// https://stackoverflow.com/a/52478680/860099函数R(x){return typeof x=='object'&&x instanceof object&&!(x个数组实例);}// https://stackoverflow.com/a/51458052/860099函数S(x){返回x!=null&&x.构造函数?。name===“对象”}// https://stackoverflow.com/a/42250981/860099函数T(x){返回x?。构造函数?。toString().indexOf(“对象”)>-1;}// https://stackoverflow.com/a/43223661/860099函数U(x){返回x?。constructor===对象;}// https://stackoverflow.com/a/46663081/860099函数V(x){return x对象实例&&x.constructor===对象;}// -------------//测试// -------------控制台日志('列: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=>控制台.log(`${f.name}:${1*f(new Date())}${1*.f(/./)}$}1*f内联)}`))控制台.log(`列图例(测试用例):1:新日期()2: /./ (注册费用)3: {}4:对象原型5:Object.create(空)6:()=>{}(函数)7:“abc”(字符串)8:3(数字)9:true(布尔值)10:空11:未定义排:1=是对象0=不是对象理论上,第1-6列应该有1,第7-11列应该有0`);
<脚本src=“https://code.jquery.com/jquery-3.5.1.min.js"完整性=“sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbj0=”crossource=“anonymous”></script><脚本src=“https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js" 完整性=“sha512-90vH1Z83AJY9DmlWa8WkjkV79yfs2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovwww==”crossource=“anonymous”></script>这艘船只提供性能测试中使用的功能,它本身不执行测试!

下面是铬的示例结果

在此处输入图像描述

10

由于对于如何正确处理这个问题似乎有很多困惑,我将留下2美分(这个答案符合规范,在所有情况下都会产生正确的结果):

原语测试:未定义 无效的 布尔值 一串

函数isPrimitive(o){返回类型o!=='object'||null}

对象不是基本体:

函数isObject(o){return!isPrimitive(o)}

或者:

函数isObject(o){返回对象的o实例}函数isPrimitic(o){return!isObject(o)}

测试任何阵列:

const isArray=(函数(){const arrayTypes=对象.create(null);arrayTypes['Array']=true;arrayTypes['Int8Array']=true;arrayTypes['Uint8Array']=true;arrayTypes['Uint8ClampedArray']=true;arrayTypes['Int16Array']=true;arrayTypes['Uint16Array']=true;arrayTypes['Int32Array']=true;arrayTypes['Uint32Array']=true;arrayTypes['BigInt64Array']=true;arrayTypes['BigUint64Array']=true;arrayTypes['Float32Array']=true;arrayTypes['Float64Array']=true;返回函数(o){如果(!o)返回false;返回!是原语(o)&&!!arrayTypes[o.constructor.name];}}());

对象测试,不包括:日期 注册Exp 布尔值 编号 字符串 功能任意数组

const isObjectStrict=(函数(){const nativeTypes=Object.create(null);nativeTypes['Date']=true;nativeTypes['RegExp']=true;nativeTypes['Boolean']=true;nativeTypes['Number']=true;nativeTypes['String']=true;nativeTypes['Function']=true;返回函数(o){if(!o)返回false;返回!是原语(o)&&!isArray(o)&&!nativeTypes[o.constructor.name];}}());
10

在阅读并尝试了许多实现之后,我注意到很少有人尝试检查以下值JSON格式,数学,文件或原型链长度超过1步的对象。

而不是检查类型我认为,如果检查尽可能简单,以避免在添加新的原语或本机对象时进行重构,那么最好将其注册为类型“object”的。

毕竟类型接线员会告诉你是JavaScript的对象,但JavaScript对对象的定义对于大多数实际场景来说过于宽泛(例如。typeof null===“对象”).下面是一个函数,用于确定变量本质上是重复两次检查的对象:

  1. 只要字符串化版本的“[对象对象]”.
    我希望函数的结果与下面的日志完全相同,所以这是我最后得出的唯一“对象性”标准。如果失败,函数将立即返回false。
  2. 替换为链中的下一个原型v=Object.getPrototypeOf(v),也可以在之后直接评估。当的新值无效的,这意味着每个原型,包括根原型(很可能是只有链内的原型)已经通过while循环中的检查,我们可以返回true。否则,将开始新的迭代。

函数isObj(v){while(Object.prototype.toString.call(v)===“[对象对象]”)if((v=Object.getPrototypeOf(v))===空)返回true返回false}console.log('FALSE:')控制台.log('[]->',isObj([]))console.log('null->',isObj(null))console.log('document->',isObj(document))console.log('JSON->',isObj(JSON))console.log('function->',isObj(function(){}))console.log('new Date()->',isObj(new Date[)])控制台.log('RegExp->',isObj(/./))console.log('TRUE:')控制台.log('{}->',isObj({}))console.log('new Object()->',isObj(new Objects()))console.log('新对象(null)->',isObj(新对象(null)))log('new Object({})->',isObj(新对象({foo:'bar'}))console.log('对象原型->',isObj(对象原型))console.log(“Object.create(null)->”,isObj(Object.create[null))console.log(“Object.create({})->”,isObj(Object.created({foo:'bar'}))console.log('deep heritance->',isObj(Object.create(Object.create({foo:'bar'})))

9

就我的代码而言,我发现这个决定与上面的一些答案相对应:

ES6变型:

const checkType=o=>对象原型.to字符串.call(o).replace(/\[|对象\s|\]/g,“”).to下壳体();

ES5变体:

功能检查类型(o){return对象原型.to字符串.调用(o).replace(/\[|object\s|\]/g,'').to下壳体();}

您可以非常简单地使用它:

checkType([])===“数组”;//真的checkType({})===“对象”;//真的checkType(1)===“数字”;//真的checkType(“”)===“字符串”;//真的checkType({}.p)===“未定义”;//真的checkType(null)===“null”;//真的

等等。。

2
  • 2
    或者切片(8,-1)可以代替替换(/\[|object\s|\]/g,'')它跑得快得可怕。
    – 托拉曼
    评论 2022年2月3日3:03
  • 1
    是的,谢谢!:) 评论 2022年4月18日6:50
8

当其他一切都失败时,我使用这个:

var isObject=函数(项){return item.constructor.name===“对象”;};
5
  • 2
    为什么要进行字符串比较,为什么不简单item.constructor===对象? 评论 2016年2月27日23:20
  • 无效的引发异常Uncaught TypeError:无法读取null(…)的属性“constructor” 评论 2016年5月17日14:08
  • @我的目标是支持旧的IE版本,为什么它在IE中不起作用?因为索引属于或者因为施工人员姓名? 评论 2018年1月24日14:15
  • 这也会因未定义而失败。 评论 2020年10月28日14:17
  • 如果你的变量不能有错误的值varName&&varName.constructor.name===“对象”如果您的变量可能有错误的值varName!=null&&varName!=未定义&&varName.constructor.name===“对象” 评论 2022年3月31日8:09
8

这将起作用。它是一个返回true、false或可能为null的函数。

const isObject=obj=>obj&&obj.constructor&&obj constructor==对象;console.log(isObject({}));//真的console.log(isObject([]));//console.log(isObject(新函数));//console.log(isObject(新编号(123));//console.log(isObject(null));//无效的

1
  • 2
    @将来你应该避免编辑答案中的代码。正如这个答案所示,测试时我确实获得了无效的作为最终测试的结果,而不是。请参阅我应该什么时候编辑代码? 评论 2017年12月13日11:36
7
if(值类型===“对象”&&value.constructor===对象){console.log(“这是一个对象”);}
1
  • 当然会的对象的Object.assign({},{constructor:null}). 评论 2020年5月14日18:17
7

如果明确要检查给定值是否为{}.

函数isObject(值){返回值&&typeof value===“对象”&&value.constructor===对象;}
7
const isObject=函数(obj){常量类型=对象类型;return type===“函数”||type==='对象'&&!!目标;};

!!对象是检查是否对象是真实的(过滤掉无效的)

不是你想要的答案吗?浏览标记的其他问题问你自己的问题.