在JavaScript中检查一个值是否为对象

2190

在JavaScript中,如何检查一个值是否为对象?


5
变量是一个变量。它可能指向一个对象。此外,您可能想定义“对象” - 正如答案和评论所显示的那样,存在各种相互矛盾的定义(例如,null是否是对象)。 - user395760
8
在我看来,你应该接受 @Daan 的回答,因为它是最好的解决方案,应该排在其他答案之上,以便首先看到。(不冒犯其他也有好回答的人)。 - tiffon
3
依我之见,这个问题的答案取决于你(寻求答案的人)认为什么是对象以及为什么要检查它。如果你试图区分数组(它们对象)和其他对象,或者是试图将标量值与“向量”分离,那么这个问题会有不同的答案。而是否应该排除null(根据typeof是一个对象)或函数(它们对象),完全取决于你为什么要检查它。这就是为什么有这么多答案,并且大多数情况下都是正确的。 - FrancescoMM
1
如果您能先说一下“是一个对象”究竟是什么意思,那就太好了。(或者明确表示您正在寻找的答案部分是为了确定“是一个对象”的各种流行含义,然后区分它们。)如果没有这个,每个人都在互相谈论而不是真正理解对方。 - Don Hatch
1
@tiffon,你觉得这个回答https://dev59.com/S2oy5IYBdhLWcg3wfeMR#52478680能不能简明扼要地回答问题?当我看到许多最高票答案的详细程度时,我感到不知所措,于是写了这篇文章。我认为它值得更多的关注。 - HalfWebDev
显示剩余5条评论
56个回答

2469

如果 typeof yourVariable === 'object',那么它就是一个对象或者 null

如果你想排除null、数组或函数,只需这样做:

if (
    typeof yourVariable === 'object' &&
    !Array.isArray(yourVariable) &&
    yourVariable !== null
) {
    executeSomeCode();
}


77
函数也是对象,应该包含在您的检查中。 - JS_Riddler
5
在这种情况下,yourVariable !== null 是否更好的做法? - hippietrail
11
似乎 typeof null == 'object'ES6 中不会被修复。他们说:“这个提案已经被拒绝了。它曾在 V8 中实现过,但结果发现它破坏了很多现有的网站。在实现“一个JavaScript”的精神中,这是不可行的。” - Konstantin Smolyanin
17
最佳方法是运行 Object.prototype.toString.call(yourVar)来检查你需要检查的变量,yourVar 是你需要检查的变量名。对于数组,Object.prototype.toString.call([1,2]) 返回 [object Array] - Jose Rui Santos
27
因为数组也被视为对象,所以您应该检查 Array.isArray(yourVariable)。因此,我认为这个回答不应该被downvote。 - Alexander Flenniken
显示剩余22条评论

952

更新:

这篇答案不完整且会给出误导性结果。例如,在JavaScript中,null 也被视为 object 类型,更不用说其他一些边缘情况了。请遵循下面的建议,并转到其他“最受欢迎(也是正确的!)答案”

typeof yourVariable === 'object' && yourVariable !== null
尝试使用typeof(var)和/或var instanceof something。编辑:本答案提供了一种检查变量属性的想法,但这并不是检查它是否为对象的万无一失的方法(毕竟根本就没有!)。由于人们倾向于在此处寻找可复制的内容而不进行任何研究,因此我强烈建议他们转向其他最受赞扬(且正确!)的答案。

147
这个答案是不正确的。typeof会返回'object',但对于空值null来说并不是一个对象;而使用Object.create(null)创建的对象无法使用instanceof进行判断。 - Nikolai
3
typeof null... object - Camilo Martin
20
数组也会被返回为“对象”,例如:someArray instanceof Object //truetypeof someArray === 'object' // true。那么如果你想检测一个数组,可以使用 Object.prototype.toString.call(someObject) === "[object Object]" 或者 "[object Array]" - Con Antonakos
9
@Jonathan,有更好的理由可以对我的回答进行负评吗?你是否有军事背景? :) - Michael Krelin - hacker
10
这并不应该被接受为答案。除了Jonathan提出的风格问题之外,它完全是错误的,并没有提到例如@matt-fenwick答案中非常重要的细微差别。 - last-child
显示剩余24条评论

627

让我们在Javascript中定义"对象"。根据MDN文档,每个值都是对象或原始类型:

primitive, primitive value

一个既不是对象也没有任何方法的数据。JavaScript 有 7 种原始数据类型:字符串、数字、大整数、布尔、未定义的值、符号和 null。

什么是原始类型?

  • 3
  • 'abc'
  • true
  • null
  • undefined

什么是对象(即非原始类型)?

  • Object.prototype
  • 所有继承自Object.prototype的对象
    • Function.prototype
      • Object
      • Function
      • function C(){} -- 用户定义的函数
    • C.prototype -- 用户定义函数的原型属性:这不是C的原型
      • new C() -- "new"一个用户定义的函数
    • Math
    • Array.prototype
      • 数组
    • {"a": 1, "b": 2} -- 使用字面符号创建的对象
    • new Number(3) -- 基本类型的包装器
    • ... 许多其他东西 ...
  • Object.create(null)
  • 所有继承自Object.create(null)的对象

如何检查一个值是否为对象

instanceof单独使用是无法起作用的,因为它会漏掉两种情况:

// oops:  isObject(Object.prototype) -> false
// oops:  isObject(Object.create(null)) -> false
function isObject(val) {
    return val instanceof Object; 
}

typeof x === 'object' 不起作用,因为会出现错误的正例(null)和错误的反例(函数):

// oops: isObject(Object) -> false
function isObject(val) {
    return (typeof val === 'object');
}

Object.prototype.toString.call无法正常工作,因为对于所有原始类型都会出现误报:

> Object.prototype.toString.call(3)
"[object Number]"

> Object.prototype.toString.call(new Number(3))
"[object Number]"

所以我使用:

function isObject(val) {
    if (val === null) { return false;}
    return ( (typeof val === 'function') || (typeof val === 'object') );
}

@Daan的答案似乎也有效:

function isObject(obj) {
  return obj === Object(obj);
}

因为根据MDN文档所述:

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


第三种看起来可行的方法(不确定是否100%有效)是使用Object.getPrototypeOf,如果其参数不是对象,则会抛出异常

// these 5 examples throw exceptions
Object.getPrototypeOf(null)
Object.getPrototypeOf(undefined)
Object.getPrototypeOf(3)
Object.getPrototypeOf('abc')
Object.getPrototypeOf(true)

// these 5 examples don't throw exceptions
Object.getPrototypeOf(Object)
Object.getPrototypeOf(Object.prototype)
Object.getPrototypeOf(Object.create(null))
Object.getPrototypeOf([])
Object.getPrototypeOf({})

46
对于数组,obj === Object(obj)返回true - Onur Yıldırım
6
var x = []; console.log(x === Object(x)); // 返回 true(翻译:在JavaScript中,创建一个空数组,并将其赋给变量x。运行console.log(x === Object(x))会返回true。) - Illuminator
22
@Illuminator数组在Javascript中是对象,正如我在我的回答中提到的。 - Matt Fenwick
6
为什么不使用 ({}).toString.apply(obj) === '[object Object]' 来区分非数组的对象和数组? - MauricioJuanes
1
val instanceof Object 对于数组返回 true。 - Илья Зеленько
显示剩余6条评论

368

underscore.js 提供了以下方法来判断一个东西是否是真正的对象:

_.isObject = function(obj) {
  return obj === Object(obj);
};

更新

由于V8中之前存在的一个bug和微小的性能优化,该方法自underscore.js 1.7.0(2014年8月)以来看起来如下:

_.isObject = function(obj) {
  var type = typeof obj;
  return type === 'function' || type === 'object' && !!obj;
};

70
在JavaScript中,数组也是一个对象,因此大多数情况下你想要排除数组:return obj === Object(obj) && Object.prototype.toString.call(obj) !== '[object Array]' - Daan
28
为什么要排除数组?它们是完整的对象。 - Nikolai
91
由于在函数输入中,大多数情况下您想要区分 {} 和 []。 - Daan
6
@Nickolai..还有用于迭代嵌套对象的方法。 - Ricky Boyce
7
好的回答。还可以处理 null。应该被接受的答案。 - tiffon
显示剩余8条评论

232

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

  • 如果myVar是对象,则返回"[object Object]"
  • 如果myVar是数组,则返回"[object Array]"
  • 等等。

关于此技术的更多信息以及为什么它是typeof的良好替代,请查看这篇文章


19
最近我了解到 typeof [] === 'object' --> true。这就是你需要用到这个方法的原因。 - Jondlm
5
@Christophe未区分基元和对象Object.prototype.toString.call(3)-> "[object Number]"Object.prototype.toString.call(new Number(3))-> "[object Number]" - Matt Fenwick
9
@MattFenwick,我认为这不是原po试图鉴定的“物体”类型。 - Christophe
3
@Christophe,你为什么这样想?在OP没有对“object”给出任何其他定义的情况下,依照ECS规范中一贯使用的定义,我认为选择它似乎是最合理的。 - Matt Fenwick
@AgentME 对,还有很多。我只是说了“等等”,列出所有的不会给我的回答增加太多价值。 - Christophe
显示剩余6条评论

204

如果只是简单地检查 ObjectArray,而不需要额外的函数调用(速度),可以使用如下方法。也可以参考这里

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字面量,对于自定义对象(例如new Datenew YourCustomObject)将返回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

4
@zupa: "a" 做了什么? - user1094081
8
好的,如果我们忽略 (!!a) 这一部分,程序会崩溃,因为 null 和 undefined 没有构造函数。 (!!a) 将它们过滤掉了。这回答了你的问题吗? - zupa
3
Boolean(a)比较长,但更加直观。只是不要使用new Boolean(a):(原因在这里!) - Jeroen Versteeg
27
很惊讶最佳答案在页面下方。这基本回答了问题 - 是否可以将其表示为以“{”字符开头的JSON内容。对于数组情况,只要你不需要支持IE < 9,你就可以使用 Array.isArray() 来确定某个东西是否是数组。它通过了你提供的所有测试案例。 - Kip
3
@BradKent 如果没有双重否定 !!aisObject(null) 将返回 null 而不是 false - AKG
显示剩余14条评论

105

我喜欢简单:

function isObject (item) {
  return (typeof item === "object" && !Array.isArray(item) && item !== null);
}
如果该项是JavaScript对象,且不是JavaScript数组,且不是null...如果这三个条件都为真,则返回true。如果其中任何一个条件失败,&&测试将短路并返回false。如果需要(根据使用null的方式),可以省略null测试。
DOCS: http://devdocs.io/javascript/operators/typeof http://devdocs.io/javascript/global_objects/object http://devdocs.io/javascript/global_objects/array/isarray http://devdocs.io/javascript/global_objects/null

4
console.log(isObject(new Date()))是什么意思?为什么日期应该是一个对象而数组不应该是? - schirrmacher
7
由于new Date()返回一个对象,而从逻辑上讲,数组不是一个对象,尽管JavaScript处理和报告它们是对象。然而,在实践中,将它们视为相等并没有什么帮助,因为它们并不相同。例如,对象没有length属性,也没有像push()这样的方法。有时候你需要给函数多种参数,需要区分数组或对象,特别是如果其他参数依赖于给定的参数类型。 - StanE
2
@StanE 数组绝对是对象。不确定您为什么认为对象不能有length属性或像push这样的方法,Object.create(Array.prototype)是一个非数组对象的微不足道的反例,它具有这些属性。数组之所以特殊,是因为它们是具有自定义[[DefineOwnProperty]]本质内部方法的异类对象,但它们仍然是对象。 - Oriol
5
@Oriol 我既没有写过数组不是对象,也没有写过对象不能有 length 属性(我是指对象字面量默认没有 length 属性)。我写的是从 逻辑 角度来说数组不是对象。我在谈论程序逻辑。有时需要检查数组是否是一个“真正”的数组而不是一个“真正”的对象。这就是 Array.isArray() 的作用。想象一下你有一个接受一个对象或对象数组的函数。检查特定属性或方法是一种不好的解决方案。原生方法总是更好的。 - StanE
2
typeof null 是 "object",而不是 "undefined"。 - 2540625
显示剩余6条评论

101

使用函数Array.isArray

function isObject(o) {
  return o !== null && typeof o === 'object' && Array.isArray(o) === false;
}

没有Array.isArray函数:

很惊讶错误答案获得了这么多赞
只有1个回答通过了我的测试!!! 这里我创建了一个简化版:

function isObject(o) {
  return o instanceof Object && o.constructor === Object;
}

对我来说,它很清晰简单,而且功能正常!这是我的测试:

console.log(isObject({}));             // Will return: true
console.log(isObject([]));             // Will return: false
console.log(isObject(null));           // Will return: false
console.log(isObject(/.*/));           // Will return: false
console.log(isObject(function () {})); // Will return: false

再强调一遍:并不是所有的答案都能通过这些测试!!!


如果你需要验证一个对象是否是特定类的实例,你需要检查它的构造函数是否属于你所需的类,比如:

function isDate(o) {
  return o instanceof Object && o.constructor === Date;
}

简单测试:

var d = new Date();
console.log(isObject(d)); // Will return: false
console.log(isDate(d));   // Will return: true

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


如果您不想创建像isDateisErrorisRegExp等函数,您可以考虑使用这些通用函数:

function isObject(o) {
  return o instanceof Object && typeof o.constructor === 'function';
}

对于之前提到的所有测试用例,它可能无法正常工作,但对于所有对象(普通或构造的)来说足够好了。


isObject 在使用 Object.create(null) 时不适用,因为 Object.create 的内部实现如此,这在这里有解释,但你可以在更复杂的实现中使用 isObject

function isObject(o, strict = true) {
  if (o === null || o === undefined) {
    return false;
  }
  const instanceOfObject = o instanceof Object;
  const typeOfObject = typeof o === 'object';
  const constructorUndefined = o.constructor === undefined;
  const constructorObject = o.constructor === Object;
  const typeOfConstructorObject = typeof o.constructor === 'function';
  let r;
  if (strict === true) {
    r = (instanceOfObject || typeOfObject) && (constructorUndefined || constructorObject);
  } else {
    r = (constructorUndefined || typeOfConstructorObject);
  }
  return r;
};

已经有一个基于这个实现的npm包v1 在npm上发布了!它适用于所有先前描述的测试案例!


1
最佳答案!适用于此处提到的许多情况。参考 - prieston
1
因为这个函数对于 isObject(myDateObject) 返回 false,所以它并不是问题的答案。它不能告诉我们一个变量是否是一个对象,只能告诉我们它是否是一个特定类的对象。这里的问题是需要一个通用函数,可以对任何对象返回 true。 - Yetanotherjosh
1
@VladimirKovpak 在我的评论中使用 Date 是不恰当的,因为回答确实讨论了 Date。但是 Date 只是无限可能的类之一,而且这个观点适用于任何其他类。例如:class Foo() {}; var x = new Foo(); isObject(x) 返回 false。我不知道 OP 的用例是什么,但很容易想象在某些情况下,必须了解 所有可能的类 并针对 每一个特定类 进行检查将是不可行的。 - Yetanotherjosh
使用 instanceof 无法判断从 Object.create(null) 创建的对象。 - CMCDragonkai
@CMCDragonkai感谢您提供这个案例!我已经更新了答案,并在npm上创建了软件包。 - cn007b
显示剩余2条评论

88

哦,我的天啊!我认为这可能比以往任何时候都更短,让我们看看:

简短而终极的代码

function isObject(obj)
{
    return obj != null && obj.constructor.name === "Object"
}

console.log(isObject({})) // returns true
console.log(isObject([])) // returns false
console.log(isObject(null)) // returns false

已解释

返回类型

typeof JavaScript对象(包括null)返回"object"

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

检查它们的构造函数

检查它们的constructor属性会返回带有它们名称的函数。

console.log(({}).constructor) // returns a function with name "Object"
console.log(([]).constructor) // returns a function with name "Array"
console.log((null).constructor) //throws an error because null does not actually have a property

介绍 Function.name

Function.name 返回一个函数的只读名称,对于闭包则返回"anonymous"

console.log(({}).constructor.name) // returns "Object"
console.log(([]).constructor.name) // returns "Array"
console.log((null).constructor.name) //throws an error because null does not actually have a property

注意:截至2018年,Function.name在IE中可能无法正常工作。

7
我非常喜欢这个,简短而且直白。就我所知,它只有一个问题。如果 obj = Object.create(null),那么为什么你会这样做呢...? - Julian Knight
如果您愿意,可以排除那种罕见情况:return obj != null && obj.constructor && obj.constructor.name === "Object"。条件'obj.constructor'返回false,因为Object.create(null)创建一个没有属性的对象,甚至没有.__proto__或.constructor。 - jkdev
2
根据您的回答,我在NodeJS中的最终(ES11)助手是:const isObject = (obj) => (obj ?? false)?.constructor?.name === "Object"; 谢谢! - szegheo

34

试试这个

if (objectName instanceof Object) {
  alert('An object');
} else {
  alert('Not an object');
}

17
为什么要对布尔值进行双重检查? - jkutianski
5
这里漏掉了两种情况:Object.prototype instanceof Object -> false. Object.create(null) instanceof Object -> false. - Matt Fenwick
1
日期怎么样?new Date() instanceof Object => true - mauron85
1
此代码假设数组为对象。 - Manoj Rana
1
иҝҷжҳҜеӣ дёәDateе’Ңж•°з»„йғҪжҳҜеҜ№иұЎгҖӮ - InSync

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接