Как эффективно подсчитать количество ключей/свойств объекта в JavaScript
Какой самый быстрый способ посчитать количество ключей/свойств объекта в JavaScript? Возможно ли сделать это без итерации по объекту, т.е. без использования следующего кода:
var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) ++count;
(Ранее в Firefox существовало магическое свойство __count__
, но оно было удалено примерно в версии 4.)
5 ответ(ов)
Вы можете использовать следующий код:
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;
Этот код добавляет метод Object.keys
для объектов, если он еще не реализован, что позволяет получить массив ключей объекта и использовать его в браузерах, которые не поддерживают этот метод по умолчанию.
Вот некоторые тесты производительности для трех методов:
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;
Этот метод немного медленнее, но значительно менее затратный по памяти, поэтому он, вероятно, лучше подходит, если вы стремитесь оптимизировать под мобильные устройства или другие ограниченные по ресурсам машины.
Использование Map вместо Object
953,839,338 операций в секунду
return mapToRead.size;
В основном, Map отслеживает свой собственный размер, поэтому мы просто возвращаем числовое значение. Этот метод значительно быстрее, чем любые другие. Если у вас есть возможность контролировать структуру данных, конвертируйте объекты в Map.
Если вы действительно сталкиваетесь с проблемой производительности, я бы предложил обернуть вызовы, которые добавляют/удаляют свойства из объекта, в функцию, которая также будет увеличивать/уменьшать соответствующее свойство (например, size
).
Вам нужно один раз вычислить начальное количество свойств и действовать исходя из этого. Если же с производительностью всё в порядке, не стоит беспокоиться. Просто оберните этот кусок кода в функцию getNumberOfProperties(object)
и на этом всё.
Чтобы подсчитать количество элементов в объектах и массивах, можно использовать несколько подходов. Вот несколько примеров:
Подсчет объектов/массивов с помощью Object.keys
// Функция для подсчета объектов и массивов
function count(obj) {
return Object.keys(obj).length;
}
Этот подход учитывает только перечисляемые свойства объекта, включаемые в массив. Он работает как для массивов, так и для обычных объектов.
Подсчет объектов/массивов с помощью цикла
function count(obj) {
var x = 0;
for (var k in obj) {
x++;
}
return x;
}
Этот метод итерирует по всем свойствам объекта с использованием цикла for...in
, увеличивая счетчик для каждого свойства. Учтите, что этот способ может также включать унаследованные свойства.
Подсчет объектов/массивов или длины строки
function count(obj) {
if (typeof(obj) === 'string' || obj instanceof String) {
return obj.toString().length;
}
return Object.keys(obj).length;
}
Этот вариант функции count
проверяет, является ли переданный аргумент строкой. Если это так, функция возвращает длину строки. В противном случае она использует Object.keys
для подсчета свойств объекта или элементов массива.
Выберите тот способ, который лучше всего подходит для вашей задачи. Если вам нужно учитывать и унаследованные свойства, может подойти второй вариант. Если вы хотите обрабатывать строки, то лучше использовать третий вариант.
Я не знаю способа сделать это. Однако, чтобы минимизировать количество итераций, вы можете проверить существование __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__
, функция будет вызвана и пересчитает значение.
Как удалить свойство из объекта JavaScript?
В чем разница между call и apply?
Доступ к свойству объекта с динамически вычисляемым именем
Сортировка свойств объекта по значениям
Проверка существования вложенного ключа объекта JavaScript