Какой самый быстрый способ подсчитать количество ключей/свойств объекта? Это можно сделать без итерации над объектом? т.е. без выполнения
var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) count++;
(Firefox действительно предоставил волшебное свойство __count__
, но это было удалено где-то около версии 4.)
Чтобы сделать это в любой ES5-совместимой среде, такой как Node, 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;
(Object.prototype.hasOwnProperty.call(obj, k))
?
hasOwnProperty
необходима. Он возвращает только свойства, установленные для самого объекта.
Если вы используете Underscore.js, вы можете использовать _. size (спасибо @douwe): _.size(obj)
В качестве альтернативы вы также можете использовать _. keys, которые могут быть понятнее для некоторых: _.keys(obj).length
Я очень рекомендую Underscore, его плотную библиотеку для выполнения множества основных вещей. Когда это возможно, они соответствуют ECMA5 и относятся к исходной реализации.
В противном случае я поддерживаю ответ @Avi. Я отредактировал его, чтобы добавить ссылку на MDC-документ, который включает в себя метод keys(), который вы можете добавить в браузер, не относящийся к ECMA5.
Стандартная реализация объекта (внутренние свойства и методы объекта ES5.1) не требует, чтобы Object
отслеживал его количество ключей/свойств, поэтому не должно быть стандартного способа определения размера Object
без явного или неявного итерации по его ключам,
Итак, вот наиболее часто используемые альтернативы:
Object.keys(obj).length;
Выполняет внутреннюю итерацию по ключам для вычисления временного массива и возвращает его длину.
Многие примеры, основанные на библиотеке в другом месте этого раздела, являются полезными идиомами в контексте их библиотеки. С точки зрения производительности, однако, нет ничего, что можно было бы сравнить с совершенным кодом без библиотеки, поскольку все эти библиотечные методы фактически инкапсулируют либо объекты Object.keys
-key for-loop, либо Object.keys
(native или shimmed).
Самая медленная часть такого цикла for, как правило, представляет .hasOwnProperty()
вызов .hasOwnProperty()
из-за служебных данных вызова функции. Поэтому, когда мне просто нужно количество записей объекта JSON, я просто пропускаю .hasOwnProperty()
если знаю, что ни один код не расширяет Object.prototype
.
В противном случае ваш код может быть немного оптимизирован, сделав k
local (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;
Является ли это быстрее или нет в данной среде, является вопрос бенчмаркинга. В любом случае можно ожидать очень ограниченного прироста производительности.
var k in myobj
повысить производительность? Насколько я знаю, только функции объявляют новую область видимости в JavaScript. Являются ли циклы исключением из этого правила?
for (var k in myobj) hasOwn.call(myobj, k) && ++count;
то есть замена оператора if на простой &&?
Если вы действительно сталкиваетесь с проблемой производительности, я бы предложил обернуть вызовы, которые добавляют/удаляют свойства в/из объекта с помощью функции, которая также увеличивает/уменьшает свойство с соответствующим именем (size?).
Вам нужно только вычислить начальное число свойств один раз и перейти оттуда. Если проблем с производительностью не существует, не беспокойтесь. Просто заверните этот бит кода в функцию getNumberOfProperties(object)
и сделайте с ним.
Как указано Avi Flax https://stackoverflow.com/questions/126100/how-to-efficiently-count-the-number-of-keys-properties-of-an-object-in-javascrip
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 в этот тип операций, но всегда полезно знать разницу;)
Я не знаю, как это сделать, но чтобы свести итерации к минимуму, вы можете попробовать проверить существование __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__
функция будет срабатывать и пересчитываться.
Object.prototype.__count__
удаляется в Gecko 1.9.3: whereswalden.com/2010/04/06/… count -property -of-objects-is-будучи удаленным /
Object.__count__
пропал, и хорошее избавление тоже.
Итерация ответа 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
_.size(obj)
Array(obj).length
: это не работает. http://jsfiddle.net/Jhy8M/
Для тех, кто имеет 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(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 = "[email protected]";
myObj.length; //output: 2
Добавлено таким образом, оно не будет отображаться в циклах for.in:
for(var i in myObj) {
console.log(i + ":" + myObj[i]);
}
Вывод:
name:John Doe
email:[email protected]
Примечание: он не работает в < IE9.
Как я решил эту проблему - создать собственную реализацию базового списка, в котором хранится запись о том, сколько элементов хранится в объекте. Это очень просто. Что-то вроде этого:
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), хотя, как и в случае с другими предлагаемыми решениями.
Если jQuery выше не работает, попробуйте
$(Object.Item).length
Object.Item
не существует
Я не думаю, что это возможно (по крайней мере, не без использования некоторых внутренних компонентов). И я не думаю, что вы выиграете, оптимизируя это.
Вы можете использовать Object.keys(data).length
чтобы найти длину объекта JSON с ключевыми данными
Я пытаюсь сделать его доступным для всех объектов следующим образом:
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(objectName).length; & Object.values(objectName).length;
Object.keys(objectName).length; & Object.values(objectName).length;
У Google Closure есть хорошая функция для этого... goog.object.getCount(obj)