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


Answers

你可以使用这个代码:

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;
Question

计算对象的键/属性数的最快方法是什么? 它可以做到这一点,而无需迭代对象? 即没有做

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

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




来自: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/definePropertyhttps://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浏览器中不起作用。







标准的对象实现( ES5.1对象的内部属性和方法 )不需要一个Object来跟踪它的键/属性的数量,所以不应该有标准的方法来确定一个Object的大小,而不需要对它的键进行显式或隐式迭代。

所以这里是最常用的选择:

1. ECMAScript的Object.keys()

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

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

2.基于图书馆的解决方案

本主题中其他许多基于库的示例在其库中都是有用的习惯用法。 然而,从性能的角度来看,与完美的无库代码相比,没有什么可以获得的,因为所有这些库方法实际上都封装了for-loop或ES5 Object.keys (本地或已填充)。

3.优化for-loop

这种for循环的最慢部分通常是.hasOwnProperty()调用,因为函数调用开销。 所以,当我只想要JSON对象的条目数时,如果我知道没有代码,也不会扩展Object.prototype ,我只需跳过.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;

在特定环境下这是否更快是一个基准问题。 无论如何,预计性能增益非常有限。




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




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

Ext.Object.getSize(myobj);

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




在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文件中有多少个函数)

也是的,我在我的例子中使用了nodejs中的_或者下划线模块

文档可以在这里Underscore.js ,以及它在github和其他各种信息的来源

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

_.size(obj)




我不知道有什么办法可以做到这一点,但为了保持迭代到最低限度,你可以尝试检查__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__函数将触发并重新计算。




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

$(Object.Item).length



Links