检查值是否为对象字面量?

32

我有一个值并想知道它是否是一个可迭代的对象字面量,在迭代它之前。

我该怎么做?


2
请定义“可迭代”。 - Bergi
14个回答

45

这应该能为你解决问题:

if( Object.prototype.toString.call( someObject ) === '[object Object]' ) {
    // do your iteration
}

如果您有兴趣,可以阅读 ECMAScript 5 第8.6.2节

每种内置对象的[[Class]]内部属性的值在此规范中都有定义。主机对象的[[Class]]内部属性的值可以是除“Arguments”、“Array”、“Boolean”、“Date”、“Error”、“Function”、“JSON”、“Math”、“Number”、“Object”、“RegExp”和“String”之外的任何字符串值。[[Class]]内部属性的值在内部用于区分不同类型的对象。请注意,本规范没有为程序提供任何访问该值的方法,除非通过Object.prototype.toString(参见15.2.4.2)。


6
在ES6中,这种方法不再保证可行,因为对象可以更改其Symbol.toStringTag属性的值,而该属性用于生成Object.prototype.toString()的返回值。请参阅http://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring中的说明。现在看起来检查某个东西是否可迭代的方法是检查它的Symbol.iterator属性是否已定义。 - Ethan
Object.prototype.toString 可被覆盖,因此不安全。 - Frederik Krautwald
8
如果它被重写了,那个开发人员应该被开除!任何原型结构都可以被其方法覆盖,并且如果您不能依赖它们,它们将毫无用处。 - Josh Mc
1
对于仍在使用此答案的人,请小心:var str; toString.call(str)如果值为undefined或null,则在IE <9和某些移动设备中会返回“object”。在应用此条件之前,先检查undefined和null。 - RAMM-HDR

9

你也可以这样做:

    if (someObject.constructor == Object) {
        // do your thing
    }

你可以在这里了解更多相关技术细节。


3
如果someObject为空,它就没有构造函数,因此会抛出TypeError。你真正想要的是上面的第一个答案。 - chilts
这比在尝试区分 js 中的数组和对象时被接受的回答要优雅得多。 - awhie29urh2
@CoDEmanX 但是Object.prototype.toString = function() { return '[object Object]' }也可以。然后从那时起,Object.prototype.toString.call( someObject ) === '[object Object]'将返回true。 - Frederik Krautwald
我认为 instanceof 运算符更好,因为它支持空值并且可以检查完整的原型层次结构。 - Aram Kocharyan
@AramKocharyan ([]) instanceof Object 返回 true。现在可以使用 someObject?.constructor === Object - Andre Figueiredo
显示剩余2条评论

3

我认为像这样的函数应该是原生的,就像Array.isArray一样:

Object.isObject = function(obj) {
    return obj && obj.constructor === this || false;
};

这个函数既没有函数调用也没有字符串比较,也不引用全局对象(如Object),因此应该非常快。虽然我认为这不会在性能密集型任务中使用,但无论如何都可以试试。
我对名称并不完全满意...也许像Object.isLiteral这样的名称会更好。
但它可能会与主机对象产生问题,不过我还没有准备好测试。

|| false 这部分是非常不必要的。 - Mulan
6
如果你希望这个函数一直返回布尔值,那么这并不是一个问题。如果 obj === null,它会返回 null。你可以使用 return obj != null && object.constructor === this; - MaxArt
3
另一种方法是 return !!(obj && obj.constructor === this) - Aram Kocharyan
最好返回 return !!obj && obj.constructor === this,这样更清晰明了。值得明确的是,你实际上只是在执行 return !!obj && obj.constructor === Object,以防有人想在其他地方使用此代码。我看到了你的速度注释,但无论如何它都非常快。 - Ryan Taylor

3
如果您使用obj instanceof Objecttypeof obj === "object",那么像new Number(3)和数组([1,2,3])这样的东西会得到错误的结果。
使用o.constructor === Object很好,但是有一种奇怪的边界情况是Object.create(null) - 事实上,它确实会给您一个普通对象,尽管不是用"正常"的方式创建的。从概念上讲,它提供了一个有效的、普通的、未装饰的对象。我们通过Object.getPrototypeOf(o) === null检查这种情况,这只对上述未装饰对象类型成立。 !!onullundefined转换为false。人们在上面抱怨它,老实说,o && ...更加简洁,除非您进行序列化,否则没有关系。尽管如此,我还是包含了它。
function isObject(o) {
  return o && o.constructor === Object
}

function isObject1(o) {
  return !!o && o.constructor === Object
}

function isObject2(o) {
  // edge case where you use Object.create(null) –– which gives an object {} with no prototype
  return !!o && (Object.getPrototypeOf(o) === null || o.constructor === Object)
}

作为一个过去主要使用!!的人,我现在认为Boolean(o)更清晰地表达了意图(同样的原因是我不使用一元运算符将字符串转换为数字,而是使用Number(str))。 - Dexygen

2
假设你有一个变量testvar,想要确认它是否为对象,但不是数组或null(因为这两者都属于类型Object)。你可以进行如下操作:
testVar instanceof Object && !Array.isArray(testVar) && testVar !== null

const testVar = new Number(2) 是什么意思? - Ryan Taylor
新的Number(2)调用会生成一个Number对象(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number),因此它将被评估为true。 - Mark

0

其实,当有像LodashUnderscore这样优秀的库存在时,你就不需要自己检查所有内容或编写自己的代码了。

在 Lodash 中,你可以通过 isPlainObject 函数轻松检查,例如:

_.isPlainObject({'a': 12});

请查看此页面:https://lodash.com/docs#isPlainObject

1
只是为了明确,Underscore没有这样的功能 - 它确实有 _.isObject 但它不检查普通对象 / 对象字面量(例如,它对数组也返回true)。 - JHH

0

奇怪的是,当调用toString()方法时,我发现子类对象的toString()返回值不同:

Object.prototype.toString.call(aThing)
"[object Object]"

aThing.toString()
"ZmPopupMenu"

这会导致一个错误的正向结果,因此我修改它以优先使用对象的toString()方法:

var str = someObject.toString
    ? someObject.toString()
    : Object.prototype.toString.call(someObject);
return str === '[object Object]';

如果一个对象的 toString 属性被重写为返回不同值的函数,例如 alert,那么它将显示该值。然而,如果 anObject 确实是一个对象,Object.prototype.toString.call( anObject ) 将始终返回字符串 [object Object]。要使 Object.prototype.toString 返回不同的内容,必须重写 Object 的原型 toString - Frederik Krautwald

0
Obj && typeof Obj === 'object' && !Array.isArray(Obj); 

0
向用户user113716:(公共实用程序)添加
function typeOfObj(obj) {
    if(typeof obj === 'function' && String(obj).search('class') === 0) return 'class';
    return Object.prototype.toString.call(obj).replace(/.*\w*\s(\w*).*/,'$1').toLowerCase();
}

if(typeof obj !== 'undefined' && typeOfObj(obj) == 'object') true;

0
const isObject = (x) => {
  return Object.prototype.toString.call(x) == "[object Object]";
}

对我来说可以。


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