web-dev-qa-db-de.com

Wie kann man die Anzahl der Schlüssel/Eigenschaften eines Objekts in JavaScript effizient zählen?

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

1302
mjs

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
2171
Avi Flax

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

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.

132
studgeek

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:

1. Object.keys () von ECMAScript

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.

  • Pros - Lesbare und saubere Syntax. Keine Bibliothek oder benutzerdefinierter Code erforderlich, außer ein Shim, wenn die native Unterstützung nicht verfügbar ist
  • Cons - Speicheraufwand aufgrund der Erstellung des Arrays.

2. Bibliotheksbasierte Lösungen

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.

3. Optimierung einer for-Schleife

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.

69
Luc125

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.

23
Confusion

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

15

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.

15
Luke Bennett

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:

  1. fügen Sie keine Funktionen in ein Objekt ein, für das Sie die Anzahl der eingegebenen Schlüssel zählen möchten

  2. 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)

13
Belldandu

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
8
hakunin

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.

6
lepe

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];
   }
}
5
Click Upvote

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
4
Flavien Volken

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.

3
Mark Rhodes

Sie können Object.keys(data).length verwenden, um die Länge eines JSON-Objekts mit Schlüsseldaten zu ermitteln

2
Codemaker

Wenn jQuery oben nicht funktioniert, versuchen Sie es

$(Object.Item).length
1
codejoecode

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'); 
1
Robert Sinclair

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.

0
amix

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
0
Taquatech