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

StackOverflow https://stackoverflow.com/questions/126100

Вопрос

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

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

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

Это было полезно?

Решение

Чтобы сделать это в любом Среда, совместимая с ES5, такие как Узел, Chrome, IE 9+, Firefox 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;

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

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

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

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

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

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

1.Object.keys от ECMAScript()

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

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

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;

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

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

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

Как заявил Ави Флэкс 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

Однако в большинстве случаев вы, возможно, не захотите включать ненумеруемые значения в операции такого типа, но всегда полезно знать разницу ;)

Чтобы выполнить итерацию по Avi, ответьте Object.keys(obj).длина правильная для объекта, к которому не привязаны функции

пример:

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)

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

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

или функциональный стиль:

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

От: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Object.defineProperty(объект, реквизит, дескриптор)

Вы можете либо добавить его ко всем своим объектам:

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(var i in myObj) {
     console.log(i + ":" + myObj[i]);
}

Выходной сигнал:

name:John Doe
email:leaked@example.com

Примечание:это не работает в < Браузеры IE9.

как отвечено выше: Object.keys(obj).length

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

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

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

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

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

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

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

$(Object.Item).length

OP не указал, является ли объект списком узлов, если это так, то вы можете просто использовать длина воздействуйте на него напрямую.Пример:

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

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

Я стараюсь сделать это доступным для всех объектов, подобных этому:

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

У Google Closure есть хорошая функция для этого...goog.object.getCount(объект)

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top