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


Was ist der schnellste Weg, um die Anzahl der Schlüssel / Eigenschaften eines Objekts zu zählen? Ist es möglich, dies zu tun, ohne über das Objekt zu iterieren? d. h. ohne zu tun

var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) count++;

(Firefox bot eine Magie __count__ Eigenschaft, aber das wurde irgendwo um Version 4 entfernt.)


1192
2017-09-24 08:56


Ursprung


Antworten:


Um dies zu tun in einer ES5-kompatiblen Umgebung, wie z Knoten, Chrome, IE 9+, FF 4+ oder Safari 5+:

Object.keys(obj).length

1982
2018-02-03 17:47



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;

140
2018-04-15 10:48



Wenn Sie verwenden Underscore.js Sie können verwenden _.Größe (Danke @douwe):
_.size(obj)

Alternativ können Sie auch verwenden _.Schlüssel was für einige klarer sein könnte:
_.keys(obj).length 

Ich empfehle Underscore, es ist eine enge Bibliothek für viele grundlegende Dinge. Wann immer möglich, stimmen sie mit ECMA5 überein und übertragen sich auf die native Implementierung.

Ansonsten unterstütze ich @ Avis Antwort. Ich habe es bearbeitet, um einen Link zum MDC-Dokument hinzuzufügen, das die Methode keys () enthält, die Sie zu Nicht-ECMA5-Browsern hinzufügen können.


126
2018-05-16 15:24



Die Standard Objektimplementierung (ES5.1 Objekt Interne Eigenschaften und Methoden) erfordert kein Object um seine Anzahl an Schlüsseln / Eigenschaften zu verfolgen, sollte es keine Standardmethode geben, um die Größe eines Schlüssels zu bestimmen Object ohne explizit oder implizit über seine Schlüssel zu iterieren.

Also hier sind die am häufigsten verwendeten Alternativen:

1. ECMAScript's Object.keys ()

Object.keys(obj).length; Werke von im Inneren Iterieren über die Schlüssel, um ein temporäres Array zu berechnen und gibt seine Länge zurück.

  • Pros - Lesbare und saubere Syntax. Wenn keine native Unterstützung verfügbar ist, ist kein Bibliotheks- oder benutzerdefinierter Code mit Ausnahme einer Unterlegscheibe erforderlich
  • Nachteile - Speicheraufwand aufgrund der Erstellung des Arrays.

2. Bibliotheksbasierte Lösungen

Viele bibliothekbasierte Beispiele an anderer Stelle in diesem Thema sind nützliche Idiome im Kontext ihrer Bibliothek. Aus Performance-Sicht gibt es jedoch nichts zu gewinnen im Vergleich zu einem perfekten No-Library-Code, da alle diese Bibliotheksmethoden entweder eine For-Schleife oder ES5 einkapseln Object.keys (nativ oder shimmed).

3. Optimieren einer For-Schleife

Das langsamster Teil von einer solchen for-Schleife ist im Allgemeinen die .hasOwnProperty() Aufruf wegen des Funktionsaufruf-Overheads. Wenn ich also nur die Anzahl der Einträge eines JSON-Objekts haben möchte, überspringe ich einfach die .hasOwnProperty() Rufen Sie an, wenn ich weiß, dass kein Code gültig ist oder nicht verlängert wird Object.prototype.

Andernfalls könnte Ihr Code sehr leicht optimiert werden k lokal (var k) und mit dem Präfix-Inkrement-Operator (++count) anstelle von Postfix.

var count = 0;
for (var k in myobj) if (myobj.hasOwnProperty(k)) ++count;

Eine andere Idee beruht auf der Zwischenspeicherung 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 gegebenen Umgebung schneller ist oder nicht, ist eine Frage des Benchmarking. Ein sehr begrenzter Leistungsgewinn ist ohnehin zu erwarten.


65
2017-09-24 09:11



Wenn Sie tatsächlich auf ein Leistungsproblem stoßen, würde ich vorschlagen, die Aufrufe, die dem Objekt Eigenschaften hinzufügen oder daraus entfernen, mit einer Funktion zu versehen, die auch eine entsprechend benannte (Größe?) Eigenschaft inkrementiert / dekrementiert.

Sie müssen nur einmal die anfängliche Anzahl von Eigenschaften berechnen und von dort weitergehen. Wenn es kein tatsächliches Leistungsproblem gibt, stören Sie nicht. Wickeln Sie einfach diesen Code in eine Funktion ein getNumberOfProperties(object) und damit fertig sein.


23
2017-09-24 09:13



Mir ist keine Möglichkeit bekannt, dies zu tun, aber um die Iterationen auf ein Minimum zu beschränken, könntest du versuchen, auf die Existenz von __count__ und wenn es nicht existiert (dh nicht Firefox), könnten Sie über das Objekt iterieren und es für die spätere Verwendung definieren, zB:

if (myobj.__count__ === undefined) {
  myobj.__count__ = ...
}

Auf diese Weise unterstützt jeder Browser __count__ würde das verwenden, und Iterationen würden nur für diejenigen durchgeführt werden, die das nicht tun. Wenn sich die Anzahl ändert und Sie dies nicht tun können, können Sie immer eine Funktion ausführen:

if (myobj.__count__ === undefined) {
  myobj.__count__ = function() { return ... }
  myobj.__count__.toString = function() { return this(); }
}

Auf diese Weise können Sie jederzeit auf myobj verweisen.__count__ Die Funktion wird ausgelöst und neu berechnet.


15
2018-01-17 11:15



Wie von Avi Flax angegeben https://stackoverflow.com/a/4889658/1047014

Object.keys(obj).length

macht den Trick für alle aufzählbaren Eigenschaften Ihres Objekts, aber auch die nicht aufzählbaren Eigenschaften, die Sie stattdessen verwenden können Object.getOwnPropertyNames. 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 angegeben Hier Dies hat die gleiche Browser-Unterstützung wie Object.keys

In den meisten Fällen möchten Sie die Nicht-Enumerables jedoch nicht in diese Art von Operationen einschließen, aber es ist immer gut, den Unterschied zu kennen;)


15
2018-03-30 01:11



Um auf Avi Flax zu antworten, ist die Antwort Object.keys (obj) .length für ein Objekt korrekt, das keine Funktionen hat

Beispiel:

obj = {"lol": "what", owo: "pfft"};
Object.keys(obj).length; // should be 2

gegen

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, in dem Sie die Anzahl der Schlüssel zählen möchten

  2. Verwenden Sie ein separates Objekt oder erstellen Sie ein neues Objekt speziell für Funktionen (wenn Sie zählen möchten, wie viele Funktionen in der Datei vorhanden sind) Object.keys(obj).length)

auch ja, ich habe das _ oder Unterstreichungsmodul von nodejs in meinem Beispiel 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)


12
2018-01-04 09:04



Für diejenigen, die Underscore.js in ihrem Projekt enthalten haben, können Sie Folgendes tun:

_({a:'', b:''}).size() // => 2

oder funktionaler Stil:

_.size({a:'', b:''}) // => 2

8
2017-08-21 03:37



Von: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Object.defineProperty (Obj, Prop, Deskriptor)

Sie können es entweder zu 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 = "leaked@example.com";
myObj.length; //output: 2

So 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:leaked@example.com

Hinweis: Es funktioniert nicht in <IE9-Browsern.


6
2018-06-28 10:04



Wie ich dieses Problem gelöst habe, besteht darin, meine eigene Implementierung einer Grundliste zu erstellen, die eine Aufzeichnung darüber speichert, wie viele Elemente in dem 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
2018-04-12 07:40