web-dev-qa-db-fra.com

Comment compter efficacement le nombre de clés/propriétés d'un objet en JavaScript?

Quel est le moyen le plus rapide de compter le nombre de clés/propriétés d'un objet? Est-il possible de le faire sans itérer sur l'objet? c'est-à-dire sans faire

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

(Firefox a fourni une propriété magique __count__, mais celle-ci a été supprimée quelque part autour de la version 4.)

1302
mjs

Pour le faire dans n'importe quel ES5-compatible environment, tel que [Node](http://nodejs.org), Chrome, IE 9+, FF 4+, or Safari 5+:

Object.keys(obj).length
2171
Avi Flax

Vous pouvez utiliser ce code:

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

Ensuite, vous pouvez également l'utiliser dans les anciens navigateurs:

var len = Object.keys(obj).length;
146
Renaat De Muynck

Si vous utilisez nderscore.js , vous pouvez utiliser _. Size (merci @douwe):
_.size(obj)

Vous pouvez également utiliser _. Keys , ce qui peut être plus clair pour certains:
_.keys(obj).length

Je recommande fortement Underscore, une bibliothèque compacte pour faire beaucoup de choses de base. Dans la mesure du possible, ils correspondent à ECMA5 et s’appliquent à l’implémentation native.

Sinon, je soutiens la réponse de @ Avi. Je l'ai modifiée pour ajouter un lien vers la documentation MDC, qui inclut la méthode keys (), que vous pouvez ajouter aux navigateurs non-ECMA5.

132
studgeek

L'implémentation d'objet standard ( ES5.1 Propriétés et méthodes internes d'objet ) ne nécessite pas de Object pour suivre son nombre de clés/propriétés; il ne devrait donc pas exister de moyen standard pour déterminer la taille d'un Object sans explicitement ou implicitement. itérant sur ses clés.

Alors voici les alternatives les plus couramment utilisées:

1. Object.keys () d'ECMAScript

Object.keys(obj).length; Fonctionne par en interne itérant sur les clés pour calculer un tableau temporaire et renvoyer sa longueur.

  • Pros - Syntaxe lisible et propre. Aucune bibliothèque ni code personnalisé requis, sauf un shim si le support natif n'est pas disponible
  • Cons - surcharge de mémoire en raison de la création du tableau.

2. Solutions basées sur la bibliothèque

De nombreux exemples basés sur les bibliothèques ailleurs dans cette rubrique sont des idiomes utiles dans le contexte de leur bibliothèque. Du point de vue des performances, toutefois, il n’ya rien à gagner par rapport à un code parfait sans bibliothèque, car toutes ces méthodes de bibliothèque encapsulent en réalité un for-loop ou un ES5 Object.keys (natif ou shimmed).

3. Optimiser une boucle for

La partie la plus lente d'une telle boucle for est généralement l'appel .hasOwnProperty(), en raison de la surcharge de l'appel de fonction. Ainsi, lorsque je veux juste le nombre d'entrées d'un objet JSON, je saute simplement l'appel .hasOwnProperty() si je sais qu'aucun code n'a prolongé ni Object.prototype.

Sinon, votre code pourrait être très légèrement optimisé en rendant k local (var k) et en utilisant l'opérateur préfixe-incrémenté (++count) au lieu de postfix.

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

Une autre idée repose sur la mise en cache de la méthode hasOwnProperty:

var hasOwn = Object.prototype.hasOwnProperty;
var count = 0;
for (var k in myobj) if (hasOwn.call(myobj, k)) ++count;

Que cela soit plus rapide ou non sur un environnement donné est une question d'analyse comparative. De toute façon, on peut s’attendre à un gain de performance très limité.

69
Luc125

Si vous rencontrez un problème de performances, je vous conseillerais d'encapsuler les appels qui ajoutent/suppriment des propriétés à/de l'objet avec une fonction qui incrémente/décrémente également une propriété (size?) Nommée de manière appropriée.

Il vous suffit de calculer le nombre initial de propriétés une fois, puis de continuer à partir de là. S'il n'y a pas de problème de performances, ne vous inquiétez pas. Enroulez ce morceau de code dans une fonction getNumberOfProperties(object) et en avez terminé.

23
Confusion

Comme indiqué par Avi Flax https://stackoverflow.com/a/4889658/1047014

Object.keys(obj).length

fera l'affaire pour toutes les propriétés énumérables sur votre objet, mais pour inclure également les propriétés non énumérables, vous pouvez utiliser à la place le Object.getOwnPropertyNames. Voici la différence:

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

Comme indiqué ici cela supporte le même navigateur que Object.keys

Cependant, dans la plupart des cas, vous pouvez ne pas vouloir inclure les éléments non énumérables dans ce type d'opération, mais il est toujours bon de connaître la différence;)

15
BenderTheOffender

Je ne suis au courant d'aucun moyen de le faire, mais pour limiter les itérations au minimum, vous pouvez essayer de vérifier l'existence de __count__ et s'il n'existe pas (c'est-à-dire pas Firefox), vous pouvez alors parcourir l'objet définissez-le pour une utilisation ultérieure, par exemple:

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

De cette façon, tout navigateur prenant en charge __count__ l'utilisera, et les itérations ne seront effectuées que pour les autres. Si le nombre change et que vous ne pouvez pas le faire, vous pouvez toujours en faire une fonction:

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

Ainsi, chaque fois que vous référencez myobj .__count__, la fonction se déclenche et se recalcule.

15
Luke Bennett

Pour ceux qui ont Underscore.js inclus dans leur projet, vous pouvez faire:

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

ou style fonctionnel:

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

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

Object.defineProperty (obj, prop, descripteur)

Vous pouvez soit l'ajouter à tous vos objets:

Object.defineProperty(Object.prototype, "length", {
    enumerable: false,
    get: function() {
        return Object.keys(this).length;
    }
});

Ou un seul objet:

var myObj = {};
Object.defineProperty(myObj, "length", {
    enumerable: false,
    get: function() {
        return Object.keys(this).length;
    }
});

Exemple:

var myObj = {};
myObj.name  = "John Doe";
myObj.email = "[email protected]";
myObj.length; //output: 2

Ajoutée de cette façon, elle ne sera pas affichée dans les boucles for..in:

for(var i in myObj) {
     console.log(i + ":" + myObj[i]);
}

Sortie:

name:John Doe
email:[email protected]

Remarque: cela ne fonctionne pas dans les navigateurs <IE9.

6
lepe

J'ai résolu ce problème en construisant ma propre implémentation d'une liste de base qui conserve un enregistrement du nombre d'éléments stockés dans l'objet. C'est très simple. Quelque chose comme ça:

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

comme répondu ci-dessus: Object.keys(obj).length

Mais: comme nous avons maintenant un vrai Map class dans ES6, je suggère de l’utiliser au lieu d’utiliser les propriétés d’un objet.

const map = new Map();
map.set("key", "value");
map.size; // THE fastest way
4
Flavien Volken

Pour ceux qui ont Ext JS 4 dans leur projet, vous pouvez faire:

Ext.Object.getSize(myobj);

L'avantage de cela est qu'il fonctionnera sur tous les navigateurs compatibles Ext (IE6-IE8 inclus). Cependant, je pense que le temps d'exécution n'est pas meilleur que O(n), comme pour les autres solutions suggérées.

3
Mark Rhodes

Vous pouvez utiliser Object.keys(data).length pour trouver la longueur d'un objet JSON contenant des données de clé.

2
Codemaker

Si jQuery ci-dessus ne fonctionne pas, essayez

$(Object.Item).length
1
codejoecode

OP n'a pas spécifié si l'objet est une liste de noeuds. Si c'est le cas, vous pouvez simplement utiliser la méthode longueur directement. Exemple:

buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen'); 
1
Robert Sinclair

Je ne pense pas que ce soit possible (du moins pas sans utiliser des composants internes). Et je ne pense pas que vous gagneriez beaucoup en optimisant cela.

0
amix

J'essaie de le rendre disponible à tous les objets comme ceci:

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