如何有效地计算 JavaScript 中对象的键/属性的数量

IT技术 javascript performance properties count key
2021-02-07 05:18:54

计算对象的键/属性数量的最快方法是什么?是否可以在不迭代对象的情况下执行此操作?即,不做:

var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) ++count;

(Firefox 确实提供了一个魔法__count__属性,但它在版本 4 左右被删除了。)

6个回答

要在任何ES5兼容环境中执行此操作,例如Node.js、Chrome、Internet Explorer 9+、Firefox 4+ 或 Safari 5+:

Object.keys(obj).length
这似乎比执行 for(至少在 Chrome 25 上)要快得多:jsperf.com/count-elements-in-object
2021-03-10 05:18:54
@GetFree 为什么这么多赞?这绝对是编码方面最快的方法。不需要额外的方法或库。在代码速度方面,显然也还不错。根本不是彻底的失败。87 次竖起大拇指失败了。
2021-03-11 05:18:54
顺便说一句……只是运行了一些测试……这个方法在 O(n) 时间内运行。for 循环并不比这种方法差多少。** 悲伤的脸 ** stackoverflow.com/questions/7956554/...
2021-03-25 05:18:54
不只是 Node.js,任何支持 ES5 的环境
2021-03-31 05:18:54
-1(如果可以的话,-200)这不仅会遍历对象,还会创建一个包含所有键的全新数组,因此它完全无法回答问题。
2021-03-31 05:18:54

您可以使用此代码:

if (!Object.keys) {
    Object.keys = function (obj) {
        var keys = [],
            k;
        for (k in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, k)) {
                keys.push(k);
            }
        }
        return keys;
    };
}

然后你也可以在旧浏览器中使用它:

var len = Object.keys(obj).length;
检查的目的是(Object.prototype.hasOwnProperty.call(obj, k))什么?
2021-03-14 05:18:54
@styfle 如果您使用for循环遍历对象的属性,您还将获得原型链中的属性。这就是为什么检查hasOwnProperty是必要的。它只返回在对象本身上设置的属性。
2021-03-23 05:18:54
2021-03-27 05:18:54
@XavierDelamotte 你是绝对正确的。虽然我的版本有效,但它是非常基本的,作为示例。Mozilla 的代码更安全。(PS:您的链接也在接受的答案中)
2021-03-27 05:18:54
@styfle 为了让它更简单,你可以只写obj.hasOwnProperty(k)(我实际上在我原来的帖子中做了这个,但后来更新了)。hasOwnProperty可用于每个对象,因为它是Object的原型的一部分,但在极少数情况下,此方法将被删除或覆盖,您可能会得到意想不到的结果。通过从Object.prototype调用它使它更健壮一点。使用的原因call是因为您想在obj而不是原型上调用方法
2021-03-28 05:18:54

如果你正在使用Underscore.js可以使用_.size感谢杜威·):

_.size(obj)

或者,您也可以使用_.keys,这对某些人来说可能更清楚:

_.keys(obj).length

我强烈推荐 Underscore.js。这是一个紧凑的库,可以做很多基本的事情。只要有可能,它们就会匹配ECMAScript 5并遵循本机实现。

否则我支持Avi Flax 的回答我对其进行了编辑以添加指向MDC文档的链接,其中包含可以添加到非 ECMAScript 5 浏览器的 keys() 方法。

_.keys(obj).length对我来说效果最好,因为我的返回对象有时是一个没有属性的普通字符串。_.size(obj)给我字符串的长度,而_.keys(obj).length返回 0。
2021-03-17 05:18:54
根据我的理解,lodash 通常比下划线更好(尽管它们做类似的事情)。
2021-03-24 05:18:54
@MerlynMorgan-Graham 如果我没记错的话,lodash 最初是下划线的一个分支......
2021-03-25 05:18:54
O(n) 复杂度Lodash 和 Underscore 在Object.keys内部使用for..in如果Object.keys未定义,下划线还会将每个键复制到循环内的数组中
2021-03-26 05:18:54
如果你使用 underscore.js 那么你应该使用 _.size 代替。好消息是,如果您以某种方式从数组切换到对象,反之亦然,结果保持不变。
2021-04-01 05:18:54

标准对象实现(ES5.1 对象内部属性和方法)不需要 anObject来跟踪其键/属性的数量,因此应该没有标准方法来确定 an 的大小Object而不显式或隐式迭代其键。

所以这里是最常用的替代方案:

1. ECMAScript 的 Object.keys()

Object.keys(obj).length;通过内部迭代键来计算临时数组并返回其长度。

  • 优点- 可读且干净的语法。如果本机支持不可用,除了垫片外,不需要库或自定义代码
  • 缺点- 由于创建数组而导致的内存开销。

2. 基于库的解决方案

本主题其他地方的许多基于库的示例在其库的上下文中都是有用的习语。然而,从性能的角度来看,与完美的无库代码相比,没有任何好处,因为所有这些库方法实际上都封装了 for 循环或 ES5 Object.keys(原生或填充)。

3.优化一个for循环

最慢的部分这样的的for循环一般是.hasOwnProperty()呼叫,因为该函数调用开销。因此,当我只想要 JSON 对象的条目数时,.hasOwnProperty()如果我知道没有代码也不会扩展 Object.prototype.

否则,您的代码可以通过创建klocal ( var k) 和使用前缀增量运算符 ( ++count) 而不是后缀来稍微优化

var count = 0;
for (var k in myobj) if (myobj.hasOwnProperty(k)) ++count;

另一个想法依赖于缓存hasOwnProperty方法:

var hasOwn = Object.prototype.hasOwnProperty;
var count = 0;
for (var k in myobj) if (hasOwn.call(myobj, k)) ++count;

在给定的环境中这是否更快是一个基准测试的问题。无论如何,可以预期的性能增益非常有限。

最后一件事你可以做:Object.getOwnPropertyNames(obj).length; 简单得多。
2021-03-28 05:18:54
这是更快吗?for (var k in myobj) hasOwn.call(myobj, k) && ++count;即用简单的&&替换if语句?
2021-04-04 05:18:54
为什么会var k in myobj提升性能?据我所知,只有函数在 JavaScript 中声明了新的作用域。内循环是这条规则的例外吗?
2021-04-08 05:18:54

以下是对三种方法的一些性能测试;

https://jsperf.com/get-the-number-of-keys-in-an-object

Object.keys().length

每秒 20,735 次操作

它非常简单和兼容,运行速度快价格昂贵,因为它创建了一个新的键数组,然后被丢弃。

return Object.keys(objectToRead).length;

遍历键

每秒 15,734 次操作

let size=0;
for(let k in objectToRead) {
  size++
}
return size;

它稍慢,但远不及内存使用量,因此如果您有兴趣针对移动设备或其他小型机器进行优化,它可能会更好。

使用 Map 而不是 Object

每秒 953,839,338 次操作

return mapToRead.size;

基本上,Map 跟踪它自己的大小,所以我们只是返回一个数字字段。它比任何其他方法都快得多。如果您可以控制对象,请将它们转换为贴图。

“使用地图而不是对象” - 这是此页面上最有用的建议。
2021-04-01 05:18:54