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

时间:2008-09-24 08:56:21

标签: javascript performance properties count key

计算对象的键/属性数的最快方法是什么?它可以在不迭代对象的情况下完成此操作吗?即没有做

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

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

22 个答案:

答案 0 :(得分:2245)

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

Object.keys(obj).length

答案 1 :(得分:149)

您可以使用此代码:

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;

答案 2 :(得分:133)

如果您使用Underscore.js,可以使用_.size(感谢@douwe):
_.size(obj)

或者您也可以使用_.keys,这可能会更清楚一些:
_.keys(obj).length

我强烈推荐使用Underscore,它是一个用于执行大量基本操作的紧凑库。只要有可能,它们就会匹配ECMA5并遵循原生实现。

否则我支持@ Avi的回答。我编辑它以添加指向MDC文档的链接,其中包含可以添加到非ECMA5浏览器的keys()方法。

答案 3 :(得分:72)

标准对象实现(ES5.1 Object Internal Properties and Methods)不需要Object来跟踪其键/属性的数量,因此应该没有标准方法来确定Object的大小没有明确或隐含地迭代其键。

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

1。 ECMAScript的Object.keys()

Object.keys(obj).length;内部工作,迭代密钥以计算临时数组并返回其长度。

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

2。基于库的解决方案

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

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;

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

答案 4 :(得分:25)

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

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

答案 5 :(得分:15)

正如Avi Flax所述https://stackoverflow.com/a/4889658/1047014

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

如上所述here,它与Object.keys

具有相同的浏览器支持

但是,在大多数情况下,您可能不希望在这些类型的操作中包含非枚举,但了解差异总是很好;)

答案 6 :(得分:15)

我不知道有什么方法可以做到这一点,但为了尽量减少迭代次数,您可以尝试检查__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__,该函数就会触发并重新计算。

答案 7 :(得分:12)

迭代Avi Flax回答Object.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计算文件中有多少函数)

  3. 也是的,我在我的例子

    中使用了nodejs中的_或下划线模块

    文档可以在http://underscorejs.org/找到,也可以在github上找到它的来源和其他各种信息

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

    _.size(obj)

答案 8 :(得分:8)

对于那些在项目中包含Underscore.js的人,您可以这样做:

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

或功能风格:

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

答案 9 :(得分:6)

来自:https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

  

Object.defineProperty(obj,prop,descriptor)

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

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

注意:它不适用于< IE9浏览器。

答案 10 :(得分:6)

如上所述:Object.keys(obj).length

但是:我们现在在ES6中有一个真正的ecgan/firestore-considerations类,我会Map使用它而不是使用对象的属性。

const map = new Map();
map.set("key", "value");
map.size; // THE fastest way

答案 11 :(得分: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];
   }
}

答案 12 :(得分:3)

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

Ext.Object.getSize(myobj);

这样做的好处是它可以在所有与Ext兼容的浏览器(包括IE6-IE8)上运行,但是,我认为运行时间并不比O(n)好,与其他建议的解决方案一样。

答案 13 :(得分:2)

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

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;

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

答案 14 :(得分:1)

如果上面的jQuery不起作用,请尝试

$(Object.Item).length

答案 15 :(得分:1)

您可以使用Object.keys(data).length来查找具有密钥数据的JSON对象的长度

答案 16 :(得分:1)

OP没有指定对象是否为nodeList,如果是,则可以直接在其上使用 length 方法。示例:

buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen'); 

答案 17 :(得分:0)

我不认为这是可能的(至少不使用一些内部)。而且我认为通过优化它不会获得太多收益。

答案 18 :(得分:0)

我尝试将它提供给所有这样的对象:

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

答案 19 :(得分:-1)

Google Closure对此有一个很好的功能... goog.object.getCount(obj)

look at goog.Object Documentation

答案 20 :(得分:-1)

您可以使用:  Object.keys(objectName).length; & Object.values(objectName).length;

答案 21 :(得分:-3)

您还可以使用

解析为Json
JSON.parse(array).lenght