1822

计算对象的键/属性数量的最快方法是什么?是否可以在不迭代对象的情况下做到这一点?即,不做:

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

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

4

20 回答 20

2925

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

Object.keys(obj).length
于 2011-02-03T17:47:20.957 回答
160

您可以使用以下代码:

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;
于 2011-04-15T10:48:18.177 回答
140

如果您使用的是Underscore.js ,您可以使用_.size感谢 douwe):

_.size(obj)

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

_.keys(obj).length

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

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

于 2011-05-16T15:24:17.140 回答
92

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

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

1. ECMAScript 的 Object.keys()

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

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

2. 基于库的解决方案

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

3.优化for循环

由于函数调用开销,这种 for 循环中最慢的部分通常是调用。.hasOwnProperty()因此,当我只想要 JSON 对象的条目数时,.hasOwnProperty()如果我知道没有代码没有也不会扩展,我就跳过调用 Object.prototype

否则,您的代码可以通过制作k本地 ( 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;

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

于 2013-05-26T21:39:23.713 回答
44

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

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;

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

使用地图而不是对象

每秒 953,839,338次操作

return mapToRead.size;

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

于 2019-10-21T18:57:32.113 回答
34

如果您实际上遇到了性能问题,我建议您使用一个函数包装向对象添加/删除属性的调用,该函数还增加/减少适当命名的(大小?)属性。

您只需要计算一次属性的初始数量并从那里继续。如果没有实际的性能问题,请不要打扰。只需将那段代码包装在一个函数中getNumberOfProperties(object)并完成它。

于 2008-09-24T09:11:22.273 回答
21

如上一个答案中所回答:Object.keys(obj).length

但是:由于我们现在在 ES6 中有一个真正的Map类,我建议使用它而不是使用对象的属性。

const map = new Map();
map.set("key", "value");
map.size; // THE fastest way
于 2018-01-19T09:04:01.127 回答
18

正如Avi Flax 所说

Object.keys(obj).length

将为您的对象上的所有可枚举属性做这个技巧,但也包括不可枚举的属性,您可以改用Object.getOwnPropertyNames. 区别如下:

var myObject = new Object();

Object.defineProperty(myObject, "nonEnumerableProp", {
  enumerable: false
});
Object.defineProperty(myObject, "enumerableProp", {
  enumerable: true
});

console.log(Object.getOwnPropertyNames(myObject).length); //outputs 2
console.log(Object.keys(myObject).length); //outputs 1

console.log(myObject.hasOwnProperty("nonEnumerableProp")); //outputs true
console.log(myObject.hasOwnProperty("enumerableProp")); //outputs true

console.log("nonEnumerableProp" in myObject); //outputs true
console.log("enumerableProp" in myObject); //outputs true

如此处所述,它具有与Object.keys.

但是,在大多数情况下,您可能不想在这些类型的操作中包含不可枚举,但知道它们的区别总是好的;)

于 2013-01-17T11:15:44.757 回答
15

要迭代Avi Flax 的 answerObject.keys(obj).length对于没有与之关联的函数的对象是正确的。

例子:

obj = {"lol": "what", owo: "pfft"};
Object.keys(obj).length; // should be 2

相对

arr = [];
obj = {"lol": "what", owo: "pfft"};
obj.omg = function(){
    _.each(obj, function(a){
        arr.push(a);
    });
};
Object.keys(obj).length; // should be 3 because it looks like this
/* obj === {"lol": "what", owo: "pfft", omg: function(){_.each(obj, function(a){arr.push(a);});}} */

避免这种情况的步骤:

  1. 不要将函数放在要计算其中键数的对象中

  2. 使用单独的对象或专门为函数创建一个新对象(如果您想计算文件中有多少个函数Object.keys(obj).length

另外,是的,我在示例中使用了Node.js 中的_or Underscore.js模块。

可以在此处找到文档及其在 GitHub 上的来源和各种其他信息。

最后是 lodash 实现https://lodash.com/docs#size

_.size(obj)

于 2014-03-30T01:11:04.663 回答
14

我不知道有什么方法可以做到这一点。但是,为了将迭代保持在最低限度,您可以尝试检查是否存在,__count__如果它不存在(即不是 Firefox),那么您可以遍历该对象并定义它以供以后使用,例如:

if (myobj.__count__ === undefined) {
  myobj.__count__ = ...
}

这样,任何支持的浏览器__count__都会使用它,并且只会对那些不支持的浏览器进行迭代。如果计数发生变化而您无法执行此操作,则始终可以将其设为函数:

if (myobj.__count__ === undefined) {
  myobj.__count__ = function() { return ... }
  myobj.__count__.toString = function() { return this(); }
}

这样,任何时候你引用 myobj. __count__该函数将触发并重新计算。

于 2008-09-24T09:13:13.343 回答
8

Object.defineProperty()

Object.defineProperty(obj, prop, 描述符)

您可以将其添加到所有对象中:

Object.defineProperty(Object.prototype, "length", {
    enumerable: false,
    get: function() {
        return Object.keys(this).length;
    }
});

或单个对象:

var myObj = {};
Object.defineProperty(myObj, "length", {
    enumerable: false,
    get: function() {
        return Object.keys(this).length;
    }
});

例子:

var myObj = {};
myObj.name  = "John Doe";
myObj.email = "leaked@example.com";
myObj.length; // Output: 2

以这种方式添加,它不会显示在for..in循环中:

for(var i in myObj) {
    console.log(i + ": " + myObj[i]);
}

输出:

name: John Doe
email: leaked@example.com

注意:它不适用于Internet Explorer 9之前的浏览器。

于 2015-08-21T03:37:26.703 回答
7

对于那些在项目中包含 Underscore.js 的人,您可以执行以下操作:

_({a:'', b:''}).size() // => 2

或功能风格:

_.size({a:'', b:''}) // => 2
于 2012-01-04T09:04:06.883 回答
5

我解决这个问题的方法是构建我自己的基本列表实现,该列表记录对象中存储了多少项目。这很简单。像这样的东西:

function BasicList()
{
   var items = {};
   this.count = 0;

   this.add = function(index, item)
   {
      items[index] = item;
      this.count++;
   }

   this.remove = function (index)
   {
      delete items[index];
      this.count--;
   }

   this.get = function(index)
   {
      if (undefined === index)
        return items;
      else
        return items[index];
   }
}
于 2011-06-28T10:04:16.987 回答
3

对于那些在他们的项目中有Ext JS 4 的人,你可以这样做:

Ext.Object.getSize(myobj);

这样做的好处是它适用于所有与 Ext JS 兼容的浏览器(包括Internet Explorer 6 - Internet Explorer 8)。但是,与其他建议的解决方案一样,我相信运行时间并不比 O(n) 好。

于 2012-04-12T07:40:14.127 回答
2

您可以使用:

Object.keys(objectName).length; 

Object.values(objectName).length;
于 2018-02-28T07:09:18.347 回答
2

这适用于数组和对象

function count(obj){
        return Object.keys(obj).length
     }
于 2022-01-30T12:35:42.830 回答
1

OP 没有指定对象是否是 nodeList。如果是,那么您可以直接在其上使用长度方法。例子:

buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen');
于 2019-06-22T05:21:07.110 回答
0

如果先前答案中的 jQuery 不起作用,请尝试

$(Object.Item).length
于 2012-09-02T01:32:01.147 回答
-3

我认为这是不可能的(至少在不使用一些内部组件的情况下是不可能的)。我不认为你会通过优化这个获得太多收益。

于 2008-09-24T09:05:38.777 回答
-3

我尝试使其可用于所有对象,如下所示:

Object.defineProperty(Object.prototype,
                      "length",
                      {
                          get() {
                              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;
                                  };
                              }
                              return Object.keys(this).length;
                      },});

console.log({"Name":"Joe", "Age":26}.length) // Returns 2
于 2018-04-14T12:51:03.220 回答