Как эффективно подсчитать количество ключей / свойств объекта в JavaScript?

каков самый быстрый способ подсчета количества ключей / свойств объекта? Можно ли это сделать без повторения объекта? то есть не делая

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

(Firefox действительно предоставил волшебство __count__ свойство, но это было удалено где-то около версии 4.)

19 ответов


сделать это в любой ES5-совместимой среде, такой как узел, Chrome, IE 9+, FF 4+ или Safari 5+:

Object.keys(obj).length

Вы можете использовать этот код:

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;

Если вы используете подчеркивания.js можно использовать _.размер (спасибо @douwe):
_.size(obj)

в качестве альтернативы вы можете также использовать _.ключи!--4--> что может быть понятнее для некоторых:
_.keys(obj).length

я настоятельно рекомендую подчеркивание, его плотная библиотека для выполнения многих основных вещей. Когда это возможно, они соответствуют ECMA5 и откладываются на собственную реализацию.

в противном случае я поддерживаю ответ @Avi. Я отредактировал его, чтобы добавить ссылка на документ MDC, который включает метод keys (), который вы можете добавить в браузеры, отличные от ECMA5.


реализация стандартного объекта (ES5.1 внутренние свойства и методы объекта) не требует Object чтобы отслеживать его количество ключей / свойств, поэтому не должно быть стандартного способа определить размер Object без явного или неявного перебора его ключей.

Итак, вот наиболее часто используемые варианты:

1. Объекта в ECMAScript.keys ()

Object.keys(obj).length; произведения внутри итерация по ключам для вычисления временного массива и возвращает его длину.

  • плюсы - читаемый и чистый синтаксис. Не требуется библиотека или пользовательский код, кроме прокладки, если собственная поддержка недоступна
  • минусы - накладные расходы памяти из-за создания массива.

2. Библиотечные решения

многие примеры на основе библиотеки в другом месте этого раздела являются полезными идиомами в контексте их библиотека. Однако с точки зрения производительности нет ничего полезного по сравнению с идеальным кодом без библиотеки, поскольку все эти методы библиотеки фактически инкапсулируют либо for-loop, либо ES5 Object.keys (родной или shimmed).

3. Оптимизация for-loop

на медленная часть такого for-loop обычно является .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;

является ли это быстрее или нет в данной среде является вопросом бенчмаркинга. В любом случае можно ожидать очень ограниченного прироста производительности.


Если вы действительно столкнулись с проблемой производительности, я бы предложил обернуть вызовы, которые добавляют / удаляют свойства в / из объекта с помощью функции, которая также увеличивает / уменьшает соответствующее имя (размер?) свойство.

вам нужно только вычислить начальное количество свойств один раз и двигаться дальше. Если нет реальной проблемы с производительностью, не беспокойтесь. Просто оберните этот бит кода в функцию getNumberOfProperties(object) и покончим с этим.


Я не знаю, как это сделать, однако, чтобы свести итерации к минимуму, вы можете попробовать проверить наличие __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__ функция будет срабатывать и пересчитывать.


как заявил 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

как заявил здесь это имеет ту же поддержку браузера, что и Object.keys

однако в большинстве случаев вы не захотите включать в этот тип nonenumerables операций, но всегда хорошо знать разницу ;)


для итерации на объекте ответа avi Flax.ключи(объект).длина верна для объекта, который не имеет привязанных к нему функций

пример:

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 в моем примере

документацию можно найти здесь http://underscorejs.org/ а также его источник на github и различные другие данные

и, наконец, реализация lodash https://lodash.com/docs#size

_.size(obj)


для тех, у кого есть подчеркивание.js, включенный в их проект, вы можете сделать:

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

или функциональном стиле:

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


Как я решил эту проблему, это создать свою собственную реализацию базового списка, который хранит запись о том, сколько элементов хранится в объекте. Все очень просто. Что-то вроде этого:--2-->

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];
   }
}

для тех, кто имеет Ext JS 4 в своем проекте, вы можете сделать:

Ext.Object.getSize(myobj);

преимущество этого заключается в том, что он будет работать на всех Ext совместимых браузерах (IE6-IE8 включены), однако, я считаю, что время работы не лучше, чем O(n), хотя, как и с другими предлагаемыми решениями.


как Ответил выше: Object.keys(obj).length

но: как у нас сейчас настоящая карта класс в ES6, я бы предлагаю использовать его вместо использования свойства объекта.

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

Я не думаю, что это возможно (по крайней мере, не без некоторых внутренних органов). И я не думаю, что вы много выиграете, оптимизируя это.


Если jQuery выше не работает, попробуйте

$(Object.Item).length

Я пытаюсь сделать его доступным для всех объектов следующим образом:

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

можно использовать Object.keys(data).length чтобы найти длину объекта JSON, имеющего ключевые данные


закрытие Google имеет хорошую функцию для этого... хорошо.объект.getCount (obj)

посмотрите на goog.Документация По Объекту


вы можете использовать: Object.keys(objectName).length; & Object.values(objectName).length;