Wie kann ich die Anzahl der Schlüssel/Eigenschaften eines Objekts am schnellsten zählen? Ist es möglich, dies ohne Iteration über das Objekt durchzuführen? ohne zu tun
var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) count++;
(Firefox hat eine magische __count__
-Eigenschaft bereitgestellt, die jedoch um Version 4 entfernt wurde.)
Um dies in einem beliebigen ES5-compatible environment
zu tun, wie [Node](http://nodejs.org), Chrome, IE 9+, FF 4+, or Safari 5+:
Object.keys(obj).length
non-ECMA5
-Browsern hinzufügen können)Sie könnten diesen Code verwenden:
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;
};
}
Dann können Sie dies auch in älteren Browsern verwenden:
var len = Object.keys(obj).length;
Wenn Sie nderscore.js verwenden, können Sie _. Size verwenden (danke @douwe):_.size(obj)
Alternativ können Sie auch _. Tasten verwenden, was für einige klarer sein könnte:_.keys(obj).length
Ich kann Underscore nur empfehlen, da es eine enge Bibliothek für viele grundlegende Dinge ist. Wann immer möglich stimmen sie mit ECMA5 überein und verschieben sich auf die native Implementierung.
Ansonsten unterstütze ich @ Avis Antwort. Ich habe es bearbeitet, um einen Link zum MDC-Dokument hinzuzufügen, der die keys () -Methode enthält, die Sie zu Nicht-ECMA5-Browsern hinzufügen können.
Die standardmäßige Objektimplementierung ( ES5.1 - Objektinterne Eigenschaften und Methoden ) erfordert keine Object
, um die Anzahl der Schlüssel/Eigenschaften zu verfolgen. Daher sollte es keine Standardmethode geben, um die Größe einer Object
explizit oder implizit zu bestimmen iteriert über seine Tasten.
Hier sind die am häufigsten verwendeten Alternativen:
Object.keys(obj).length;
Funktioniert durch intern Durchlaufen der Schlüssel, um ein temporäres Array zu berechnen, und gibt dessen Länge zurück.
Viele bibliotheksbasierte Beispiele an anderer Stelle in diesem Thema sind nützliche Redewendungen im Kontext ihrer Bibliothek. Im Hinblick auf die Leistung ist jedoch im Vergleich zu einem perfekten No-Library-Code nichts zu gewinnen, da all diese Bibliotheksmethoden tatsächlich entweder eine for-loop oder ES5 Object.keys
(native oder shimmed) enthalten.
Der langsamste Teil einer solchen for-Schleife ist aufgrund des Funktionsaufruf-Overheads im Allgemeinen der Aufruf .hasOwnProperty()
. Wenn ich also nur die Anzahl der Einträge eines JSON-Objekts haben möchte, überspringe ich einfach den Aufruf .hasOwnProperty()
, wenn ich weiß, dass kein Code Object.prototype
erweitert hat.
Andernfalls könnte Ihr Code geringfügig optimiert werden, indem Sie k
local (var k
) und den Präfix-Inkrement-Operator (++count
) anstelle von Postfix verwenden.
var count = 0;
for (var k in myobj) if (myobj.hasOwnProperty(k)) ++count;
Eine andere Idee beruht auf dem Zwischenspeichern der hasOwnProperty
-Methode:
var hasOwn = Object.prototype.hasOwnProperty;
var count = 0;
for (var k in myobj) if (hasOwn.call(myobj, k)) ++count;
Ob dies in einer bestimmten Umgebung schneller ist oder nicht, ist eine Frage des Benchmarking. Ein sehr begrenzter Leistungsgewinn ist ohnehin zu erwarten.
Wenn Sie tatsächlich auf ein Leistungsproblem stoßen, würde ich vorschlagen, die Aufrufe, die dem Objekt Eigenschaften hinzufügen/entfernen, mit einer Funktion zu umschließen, die auch eine entsprechend benannte (size?) Eigenschaft erhöht/dekrementiert.
Sie müssen nur einmal die anfängliche Anzahl von Eigenschaften berechnen und von dort fortfahren. Wenn es kein tatsächliches Leistungsproblem gibt, machen Sie sich keine Sorgen. Wickeln Sie einfach dieses Bit in eine Funktion getNumberOfProperties(object)
und machen Sie es fertig.
Wie von Avi Flax angegeben https://stackoverflow.com/a/4889658/1047014
Object.keys(obj).length
führt den Trick für alle aufzählbaren Eigenschaften für Ihr Objekt aus, aber auch die nicht auflösbaren Eigenschaften, die Sie verwenden können, können Sie stattdessen Object.getOwnPropertyNames
verwenden. Hier ist der Unterschied:
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
Wie gesagt, here hat dies die gleiche Browserunterstützung wie Object.keys
.
In den meisten Fällen möchten Sie jedoch möglicherweise nicht die nicht-nummerierbaren Elemente in diese Art von Vorgängen einschließen, aber es ist immer gut, den Unterschied zu kennen;)
Mir ist keine Möglichkeit bekannt, dies zu tun. Um die Iterationen jedoch auf ein Minimum zu beschränken, könnten Sie versuchen, die Existenz von __count__
zu überprüfen. Wenn dies nicht der Fall ist (dh nicht Firefox), könnten Sie das Objekt durchlaufen Definiere es für eine spätere Verwendung, zB:
if (myobj.__count__ === undefined) {
myobj.__count__ = ...
}
Auf diese Weise würde jeder Browser, der __count__
unterstützt, dies verwenden, und Iterationen würden nur für diejenigen ausgeführt, die dies nicht tun. Wenn sich die Anzahl ändert und Sie dies nicht tun können, können Sie es immer zu einer Funktion machen:
if (myobj.__count__ === undefined) {
myobj.__count__ = function() { return ... }
myobj.__count__.toString = function() { return this(); }
}
Immer wenn Sie auf myobj .__count__
verweisen, wird die Funktion ausgelöst und neu berechnet.
Um auf Avi-Flachs zu iterieren, beantworten Sie Object.keys (obj) .length für ein Objekt, an das keine Funktionen gebunden sind
beispiel:
obj = {"lol": "what", owo: "pfft"};
Object.keys(obj).length; // should be 2
versus
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);});}} */
schritte, um dies zu vermeiden:
fügen Sie keine Funktionen in ein Objekt ein, für das Sie die Anzahl der eingegebenen Schlüssel zählen möchten
verwenden Sie ein separates Objekt oder erstellen Sie ein neues Objekt speziell für Funktionen (wenn Sie mit Object.keys(obj).length
zählen möchten, wie viele Funktionen sich in der Datei befinden)
auch ja, ich habe in meinem Beispiel das Modul _ oder Unterstrich von nodejs verwendet
dokumentation finden Sie hier http://underscorejs.org/ sowie seine Quelle auf Github und verschiedene andere Informationen
Und schließlich eine lodash-Implementierung https://lodash.com/docs#size
_.size(obj)
Für diejenigen, die Underscore.js in ihrem Projekt enthalten, können Sie Folgendes tun:
_({a:'', b:''}).size() // => 2
oder funktionaler Stil:
_.size({a:'', b:''}) // => 2
Von: https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Object.defineProperty (obj, prop, descriptor)
Sie können es entweder allen Ihren Objekten hinzufügen:
Object.defineProperty(Object.prototype, "length", {
enumerable: false,
get: function() {
return Object.keys(this).length;
}
});
Oder ein einzelnes Objekt:
var myObj = {};
Object.defineProperty(myObj, "length", {
enumerable: false,
get: function() {
return Object.keys(this).length;
}
});
Beispiel:
var myObj = {};
myObj.name = "John Doe";
myObj.email = "[email protected]";
myObj.length; //output: 2
Auf diese Weise hinzugefügt, wird es nicht in for..in-Schleifen angezeigt:
for(var i in myObj) {
console.log(i + ":" + myObj[i]);
}
Ausgabe:
name:John Doe
email:[email protected]
Hinweis: In <IE9-Browsern funktioniert es nicht.
Wie ich dieses Problem gelöst habe, ist das Erstellen meiner eigenen Implementierung einer Basisliste, in der aufgezeichnet wird, wie viele Elemente im Objekt gespeichert sind. Es ist sehr einfach. Etwas wie das:
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];
}
}
wie oben beantwortet: Object.keys(obj).length
Aber: Da wir jetzt eine echte Map - Klasse in ES6 haben, würde ich vorschlagen statt der Eigenschaften eines Objekts zu verwenden.
const map = new Map();
map.set("key", "value");
map.size; // THE fastest way
Für diejenigen, die Ext JS 4 in ihrem Projekt haben, können Sie Folgendes tun:
Ext.Object.getSize(myobj);
Der Vorteil davon ist, dass es mit allen Ext-kompatiblen Browsern (einschließlich IE6-IE8) funktioniert. Ich glaube jedoch, dass die Laufzeit nicht besser als O(n) ist, wie bei anderen vorgeschlagenen Lösungen.
Sie können Object.keys(data).length
verwenden, um die Länge eines JSON-Objekts mit Schlüsseldaten zu ermitteln
Wenn jQuery oben nicht funktioniert, versuchen Sie es
$(Object.Item).length
OP hat nicht angegeben, ob das Objekt eine NodeList ist. Ist dies der Fall, können Sie die Methode length direkt verwenden. Beispiel:
buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen');
Ich glaube nicht, dass dies möglich ist (zumindest nicht ohne einige interne Elemente). Und ich glaube nicht, dass Sie durch die Optimierung dieser Einstellung viel gewinnen würden.
Ich versuche, es allen Objekten so zur Verfügung zu stellen:
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