这个函数如何确定一个对象是否为空?

8

我在研究jQuery源代码时发现他们使用了以下代码片段来检测JavaScript对象是否为空。

function isMyObjEmpty( obj ) {
    var name;
    for (name in obj ) {
        return false;
    }
    return true;
}

有人能解释一下这个代码为什么可行吗?我就是不明白这样会返回true的原因。


如果在obj上定义了一个或多个属性,则返回false,表示对象不为空。如果执行到最后,意味着没有找到任何属性,因此表示对象为空。 - Kevin B
1
好问题,正是我喜欢在StackOverflow上看到的类型。不是“这里有一些有问题的代码(可能还不完整),你们能帮我修复一下,这样我就可以在工作中表现得像我自己完成了它”,而是一个真正的编程问题,我很感兴趣...点赞! - iAmClownShoe
6个回答

16

为什么它起作用:

这里使用了一个 for...in 循环来遍历对象的属性。

如果对象有任何属性,它会进入循环并返回false

如果对象没有属性,则不会进入循环,并返回true

为什么它不起作用:

请注意,存在一种情况它无法工作。for..in 循环只通过可枚举属性,因此从技术上讲,对象可以是非空的,但它仍会返回false。可以定义一个属性不可枚举,从而欺骗这个方法。 这是有问题的例子

正确的说法是,该方法检查对象是否具有任何可枚举属性。

文档怎么说:

您可以在此处找到该方法的文档

描述:检查对象是否为空(不包含任何可枚举属性)。

我个人认为他们称该方法为isEmptyObject有些奇怪。我认为更适合的名称应该是hasNoEnumerableProperties

如果您真的想检查对象是否为空怎么办?

在JS的新实现中,可以使用Object.getOwnPropertyNamesgetOwnPropertyNames获取所有属性,可枚举或不可枚举。

你可以使用 Object.getOwnPropertyNames(myObject).length===0 实现isMyObjEmpty,这将检查对象是否具有属性,包括可枚举和不可枚举属性。
然而,这并不检查原型属性。这可能是期望的行为,也可能不是。你可以查看我与 theshadowmonkey 的讨论。通过在原型链上递归调用 Object.getPrototypeOf 并检查原型属性,可以轻松解决此问题。

1
如果在obj中找到了name,那么obj中就有东西,而且不是空的;如果无法找到,它将返回true,表示obj为空。

0
也许不是这样,但我认为混淆的原因在于 obj 中的键“name”。实际上,它并不是在对象中寻找名为“name”的键,而是将任何键分配给他们称之为 name 的变量。因此,如果它在对象中找到任何内容,它将返回 false 并确认它确实不是一个空对象。但如果它在对象中没有找到任何内容,它将返回 true,这意味着你的对象是空的。

0

关键在于for..in循环遍历对象的每个属性,但不包括其他内容。如果对象中没有任何内容,则该循环永远不会运行,因此“return false”行永远不会被执行。程序然后继续执行下一行,告诉它返回true。

(这本身就引出了一个有趣的问题。那个for..in循环是否应该包含hasOwnProperty()检查?或者该函数是否实际上意图捕获非自有属性并根据此计算对象为空?)


你好,欢迎来到StackOverflow!如果您查看我的答案,您可以看到为什么它在所有情况下都不会迭代对象的每个属性以及何时发生,我还提供了一个链接到for...in循环的定义,这样您就可以看到确切的情况。如果您查看@theshadowmonkey的答案评论,我们在这种情况下有一个有趣的讨论,涉及“自有属性”。 - Benjamin Gruenbaum

0

因此,在某些情况下可能无法正常工作,例如当您检查空对象并且该特定对象是全局对象的子对象时,即使它为空,您也将始终返回非空。 - theshadowmonkey
@BenjaminGruenbaum 在你编写的函数中,使用上述的 for..in 方法是否更加稳妥可靠? - theshadowmonkey
也许一些人,像广为人知的 Douglas Crockford,认为 for...in 循环必须有 hasOwnProperty 检查。但我个人认为这样做非常局限。这里有一些关于此的讨论:https://www.youtube.com/watch?v=taaEzHI9xyY&t=1h4m28s。 - Benjamin Gruenbaum
难道不像那个讨论一样具有限制性吗?除非您使用原型继承,否则在大多数情况下通过使用“hasOwnProperty”,您会减少很多风险。 - theshadowmonkey
再次强调,这取决于情况。我认为,在其原型上具有属性的对象_不是_空的,而添加hasOwnProperty检查通常是一个好建议,但在这种情况下我并不认为如此。如果我有一个带有原型动物的狗,并且该动物具有默认名称、大小、方法或任何其他属性。我认为我的狗对象不是空的。你可能会有不同的看法,由于这涉及语义问题,我认为这没有问题。我只是想提出这个话题,以便未来的读者能够意识到这一点 :) - Benjamin Gruenbaum
是的,那对我有帮助。因为我总是使用检查的原因是,我从不使用原型继承来组织我的代码,因此添加额外的检查对我来说似乎更加清洁。但是,我认为当你的应用程序使用原型继承的强大功能时,你可以安全地省略它。我的大多数情况都是在尝试迭代 DOM 对象(如事件)时发生的。因此,例如,获取一个点击事件对象并查看它所具有的成员 :) - theshadowmonkey

-1

当对象为空时,它什么时候会返回 true,当然是空的时候。

isMyObjEmpty({});

它是如何工作的?通过使用for...in


for...in

概述

按任意顺序迭代对象的可枚举属性。对于每个不同的属性,可以执行语句。

因此,如果没有属性,它将不会进入for in循环。循环实际上应该检查hasOwnProperty(),因为这可能导致错误的结果。


伙计们他是对的。停止对他进行负面评价。我点赞了,因为这个被不当地点踩了。 - iAmClownShoe
2
@iAmClownShoe - 在被投票反对的时候,答案只是一个简短的草稿,内容是“当对象为空时,它会返回true。isMyObjEmpty({});”。如果你发布了不充分的FGITW答案,那么被投票反对就是你要承担的风险。 - Martin Smith
好的,我之前可能错过了它的编辑。无论如何,既然他已经很好地回答了问题,那么这些负评可以被移除了。 - iAmClownShoe

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