Как эффективно подсчитать количество ключей / свойств объекта в JavaScript?
Какой самый быстрый способ подсчитать количество ключей / свойств объекта? Можно ли сделать это без перебора объекта? т.е. без выполнения
var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) count++;
(Firefox обеспечил магию __count__
свойство, но это было удалено где-то около версии 4.)
24 ответа
Чтобы сделать это в любой ES5-совместимой среде, такой как Node, Chrome, IE 9+, FF 4+ или Safari 5+:
Object.keys(obj).length
- Совместимость браузера
- Object.keys документация
- (включает метод, который вы можете добавить в браузеры не ECMA5)
Вы можете использовать этот код:
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;
Если вы используете http://underscorejs.org/, вы можете использовать _.size (спасибо @douwe):_.size(obj)
В качестве альтернативы вы также можете использовать _.keys, которые могут быть более понятными для некоторых:_.keys(obj).length
Я настоятельно рекомендую Underscore, его компактную библиотеку для выполнения множества базовых задач. По возможности, они соответствуют ECMA5 и относятся к собственной реализации.
В противном случае я поддерживаю ответ @Avi. Я отредактировал его, добавив ссылку на документ MDC, который включает метод keys(), который вы можете добавить в браузеры не-ECMA5.
Вот несколько тестов производительности для трех методов;
https://jsperf.com/get-the-number-of-keys-in-an-object
Object.keys(). Length
20735 операций в секунду
Очень просто и совместимо. Работает быстро, но дорого, поскольку создает новый массив ключей, который затем выбрасывается.
return Object.keys(objectToRead).length;
пройтись по клавишам
15734 операции в секунду
let size=0;
for(let k in objectToRead) {
size++
}
return size;
Немного медленнее, но совсем не по использованию памяти, поэтому, вероятно, лучше, если вы заинтересованы в оптимизации для мобильных или других небольших машин.
Использование карты вместо объекта
953839338 операций в секунду
return mapToRead.size;
По сути, Map отслеживает свой размер, поэтому мы просто возвращаем числовое поле. Намного, намного быстрее, чем любой другой метод. Если у вас есть контроль над объектом, вместо этого преобразуйте их в карты.
Стандартная реализация объекта ( внутренние свойства и методы объекта ES5.1) не требует Object
отслеживать его количество ключей / свойств, поэтому не должно быть никакого стандартного способа определения размера Object
без явного или неявного перебора его ключей.
Итак, вот наиболее часто используемые альтернативы:
1. ECMAScript Object.keys()
Object.keys(obj).length;
Работает путем внутренней перебора ключей для вычисления временного массива и возвращает его длину.
- Плюсы - Читаемый и чистый синтаксис. Не требуется никакой библиотеки или пользовательского кода, кроме прокладки, если встроенная поддержка недоступна
- Минусы - накладные расходы памяти из-за создания массива.
2. Библиотечные решения
Многие основанные на библиотеках примеры в других частях этой темы являются полезными идиомами в контексте их библиотеки. Однако с точки зрения производительности выиграть нечего по сравнению с идеальным кодом без библиотек, поскольку все эти библиотечные методы фактически инкапсулируют цикл for или ES5. Object.keys
(родной или подкладочный).
3. Оптимизация цикла 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)
и покончим с этим.
это работает как для массивов, так и для объектов
function count(obj){
return Object.keys(obj).length
}
Как заявил Ави Лен /questions/24714349/kak-effektivno-podschitat-kolichestvo-klyuchej-svojstv-obekta-v-javascript/24714373#24714373
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 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);});}} */
шаги, чтобы избежать этого:
не помещайте функции в объект, который вы хотите посчитать количество ключей в
использовать отдельный объект или создать новый объект специально для функций (если вы хотите подсчитать, сколько функций в файле, используя
Object.keys(obj).length
)
также да, я использовал _ или модуль подчеркивания из nodejs в моем примере
документацию можно найти здесь http://underscorejs.org/ а также ее источник на github и другую другую информацию
И, наконец, реализация lodash https://lodash.com/docs
_.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__
функция сработает и пересчитает.
От: 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
Примечание: он не работает в браузерах
Для тех, у кого есть Underscore.js, включенный в их проект, вы можете сделать:
_({a:'', b:''}).size() // => 2
или функциональный стиль:
_.size({a:'', b:''}) // => 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(objectName).length;
& Object.values(objectName).length;
Если jQuery выше не работает, то попробуйте
$(Object.Item).length
OP не указал, является ли объект нодлистом, если это так, то вы можете просто использовать метод длины непосредственно для него. Пример:
buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen');
Ты можешь использовать Object.keys(data).length
найти длину объекта JSON, имеющего ключевые данные
У Google Closure есть хорошая функция для этого... goog.object.getCount(obj)
Вы также можете разобрать Json, используя
JSON.parse(array).lenght
Я пытаюсь сделать его доступным для всех объектов следующим образом:
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
Я не думаю, что это возможно (по крайней мере, без использования некоторых внутренних). И я не думаю, что вы бы много выиграли, оптимизировав это.