对象是空的吗?

IT技术 javascript
2021-01-24 20:40:08

检查对象是否为空的最快方法是什么?

有没有比这更快更好的方法:

function count_obj(obj){
    var i = 0;
    for(var key in obj){
        ++i;
    }

    return i;
}
6个回答

对于 ECMAScript5(并非所有浏览器都支持),您可以使用:

Object.keys(obj).length === 0
CrockfordgetOwnPropertyNames推荐@CMS 据他介绍,这种方法是专门为 Caja(以及其他安全框架,我猜)引入的语言。因此,此方法有可能在某些环境中不可用或将不可用。
2021-03-20 20:40:08
从语义上讲,我认为,具有零可枚举属性的对象应该被视为“空”(因为不可枚举的声明属性可能意味着“私有”),因此Object.keys.length可能是正确的方法。
2021-03-21 20:40:08
令人难以置信的是 Object.isEmpty() 还不是 javascript 的一部分
2021-03-26 20:40:08
更合适的 ES5 解决方案是Object.getOwnPropertyNames(obj).length == 0因为Object.keys只获取可枚举的属性。在 ES5 中,我们拥有定义属性的能力,我们可以拥有一个具有不可枚举属性的对象,并且Object.keys只会返回一个空数组......Object.getOwnPropertyNames返回一个包含对象所有属性的数组,即使它们不可枚举.
2021-03-30 20:40:08
这个答案现在适用于所有现代浏览器绝对是最好的,除非你需要支持 IE8-。
2021-03-30 20:40:08

我假设空的意思是“没有自己的属性”。

// Speed up calls to hasOwnProperty
var hasOwnProperty = Object.prototype.hasOwnProperty;

function isEmpty(obj) {

    // null and undefined are "empty"
    if (obj == null) return true;

    // Assume if it has a length property with a non-zero value
    // that that property is correct.
    if (obj.length > 0)    return false;
    if (obj.length === 0)  return true;

    // If it isn't an object at this point
    // it is empty, but it can't be anything *but* empty
    // Is it empty?  Depends on your application.
    if (typeof obj !== "object") return true;

    // Otherwise, does it have any properties of its own?
    // Note that this doesn't handle
    // toString and valueOf enumeration bugs in IE < 9
    for (var key in obj) {
        if (hasOwnProperty.call(obj, key)) return false;
    }

    return true;
}

例子:

isEmpty(""), // true
isEmpty(33), // true (arguably could be a TypeError)
isEmpty([]), // true
isEmpty({}), // true
isEmpty({length: 0, custom_property: []}), // true

isEmpty("Hello"), // false
isEmpty([1,2,3]), // false
isEmpty({test: 1}), // false
isEmpty({length: 3, custom_property: [1,2,3]}) // false

如果你只需要处理ECMAScript5 浏览器,你可以使用Object.getOwnPropertyNames代替hasOwnProperty循环:

if (Object.getOwnPropertyNames(obj).length > 0) return false;

这将确保即使对象只有不可枚举的属性,isEmpty仍然会给你正确的结果。

@frequent -var hasOwnProp可能也有用:-) 我们希望避免尽可能多的查找(以防在性能很重要的地方调用它[如果真的很重要,只有分析会告诉你每个查询的最快方式)平台])。
2021-03-13 20:40:08
@yckart - 你是绝对正确的!我很惊讶这个 bug 能存活这么久。感谢您帮助使答案更好!
2021-03-19 20:40:08
@pgreen2 - 好收获!我已更新示例以包含对 0 的显式检查 - 感谢您帮助改进答案!
2021-03-25 20:40:08
@SeanVieira is_empty({length: 0, custom_property: []}) 返回 false。我不确定您希望代码如何工作,但如果您添加: if (obj.length === 0) return true; if (obj.length && obj.length > 0) return false; 这是正确的
2021-04-03 20:40:08
@NehaChoudhary - 如果你看看这个 jsFiddle,你会看到这种情况是为了避免这种情况。
2021-04-05 20:40:08

编辑:请注意,您可能应该使用ES5 解决方案而不是这个,因为如今 ES5 支持很普遍不过它仍然适用于 jQuery。


简单和跨浏览器的方式是使用jQuery.isEmptyObject

if ($.isEmptyObject(obj))
{
    // do something
}

更多:http : //api.jquery.com/jQuery.isEmptyObject/

不过你需要jquery。

我怀疑这仍然是真的,如果它曾经是(代码非常标准) - 但如果你有一个例子并且可以在 IE8 上进行验证,你应该使用 jQuery 提交错误报告。他们对此非常认真。
2021-03-23 20:40:08
@Pier 我觉得你在这里故意迟钝。跨浏览器并不表示它包含在浏览器本身中,而只是表示它可以在主要接受的浏览器中普遍工作。
2021-03-23 20:40:08
它不是跨浏览器,因为浏览器不包含 jQuery。
2021-03-25 20:40:08
并非所有浏览器都支持 ES5 解决方案(目前 - 至少是 AFAIK),因此如果您已经在使用 jQuery(许多网站都在使用),那么这个解决方案是有意义的。此外,jQuery 比 Jakob 的解决方案更有效(尽管在大多数情况下它并不重要),因为它在计算长度之前不会遍历整个对象 -一旦找到键,它就会返回false
2021-04-01 20:40:08
我很高兴 jQuery 选项是一个“示例性的,值得额外奖励”的选项,而不是原生 ES5 解决方案我想这个答案在某些情况下仍然有用。
2021-04-09 20:40:08

下划线lodash各有一个方便的isEmpty()功能,如果你不介意添加额外的库。

_.isEmpty({});
或者对于已经包含下划线的人;)
2021-03-27 20:40:08
后期评论:至于 2016 你可以只使用 lodash isEmpty(你不需要导入所有的 lodash,你现在可以从中导入一个方法,它在 npm 中被分成多个微包)。
2021-03-27 20:40:08
是的,或者您可以导入node_modules/*并忽略您对任何插件的任何依赖</sarcasm>
2021-04-01 20:40:08
您还可以检查源代码并查看是否需要导入:github.com/lodash/lodash/blob/4.17.14/lodash.js#L11479
2021-04-06 20:40:08
自己动手的解决方案非常适合学习语言的复杂性,但对于生产用途,最好利用强大的库,例如 lodash。Lodash 已经针对性能和极端情况进行了压力测试。_.isEmpty() 很方便,因为它支持对象、数组,几乎任何东西。
2021-04-09 20:40:08

让我们把这个婴儿放在床上;在 Node、Chrome、Firefox 和 IE 9 下进行测试,很明显对于大多数用例:

  • (for...in...) 是最快的选项!
  • Object.keys(obj).length 对于空对象慢 10 倍
  • JSON.stringify(obj).length 总是最慢的(不足为奇)
  • Object.getOwnPropertyNames(obj).length 花费的时间比 Object.keys(obj).length在某些系统上可能要长得多。

底线性能明智,使用:

function isEmpty(obj) { 
   for (var x in obj) { return false; }
   return true;
}

或者

function isEmpty(obj) {
   for (var x in obj) { if (obj.hasOwnProperty(x))  return false; }
   return true;
}

节点下的结果:

  • 第一个结果: return (Object.keys(obj).length === 0)
  • 第二个结果: for (var x in obj) { return false; }...
  • 第三个结果: for (var x in obj) { if (obj.hasOwnProperty(x)) return false; }...
  • 第四个结果: return ('{}' === JSON.stringify(obj))

测试具有 0 个键的对象 0.00018 0.000015 0.000015 0.000324

测试具有 1 个键的对象 0.000346 0.000458 0.000577 0.000657

测试具有 2 个键的对象 0.000375 0.00046 0.000565 0.000773

测试具有 3 个键的对象 0.000406 0.000476 0.000577 0.000904

测试具有 4 个键的对象 0.000435 0.000487 0.000589 0.001031

测试具有 5 个键的对象 0.000465 0.000501 0.000604 0.001148

测试具有 6 个键的对象 0.000492 0.000511 0.000618 0.001269

测试具有 7 个键的对象 0.000528 0.000527 0.000637 0.00138

测试具有 8 个键的对象 0.000565 0.000538 0.000647 0.00159

测试具有 100 个键的对象 0.003718 0.00243 0.002535 0.01381

测试具有 1000 个键的对象 0.0337 0.0193 0.0194 0.1337

请注意,如果您的典型用例测试具有少量键的非空对象,并且您很少测试空对象或具有 10 个或更多键的对象,请考虑使用 Object.keys(obj).length 选项。- 否则采用更通用的 (for... in...) 实现。

请注意,Firefox 似乎对 Object.keys(obj).length 和 Object.getOwnPropertyNames(obj).length 提供了更快的支持,使其成为任何非空对象的更好选择,但是当涉及到空对象时,( for...in...) 速度快了 10 倍。

我的 2 美分是 Object.keys(obj).length 是一个糟糕的主意,因为它创建了一个键对象只是为了计算里面有多少键,而不是销毁它!为了创建该对象,他需要循环公开键...那么为什么要使用它而不是 (for... in...) 选项:)

var a = {};

function timeit(func,count) {
   if (!count) count = 100000;
   var start = Date.now();
   for (i=0;i<count;i++) func();
   var end = Date.now();
   var duration = end - start;
   console.log(duration/count)
}

function isEmpty1() {
    return (Object.keys(a).length === 0)
}
function isEmpty2() {
    for (x in a) { return false; }
    return true;
}
function isEmpty3() {
    for (x in a) { if (a.hasOwnProperty(x))  return false; }
    return true;
}
function isEmpty4() {
    return ('{}' === JSON.stringify(a))
}


for (var j=0;j<10;j++) {
   a = {}
   for (var i=0;i<j;i++) a[i] = i;
   console.log('Testing for Object with '+Object.keys(a).length+' keys')
   timeit(isEmpty1);
   timeit(isEmpty2);
   timeit(isEmpty3);
   timeit(isEmpty4);
}

a = {}
for (var i=0;i<100;i++) a[i] = i;
console.log('Testing for Object with '+Object.keys(a).length+' keys')
timeit(isEmpty1);
timeit(isEmpty2);
timeit(isEmpty3);
timeit(isEmpty4, 10000);

a = {}
for (var i=0;i<1000;i++) a[i] = i;
console.log('Testing for Object with '+Object.keys(a).length+' keys')
timeit(isEmpty1,10000);
timeit(isEmpty2,10000);
timeit(isEmpty3,10000);
timeit(isEmpty4,10000);

for (x in a) { return false; }可以是无块的单语句for语句。这意味着,您可以通过删除{}. Kindda,无用的信息。但是您的 6 位计时精度可能会引起注意。
2021-03-28 20:40:08