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.)
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
non-ECMA5
)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;
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.
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:
Object.keys(obj).length;
Fonctionne par en interne itérant sur les clés pour calculer un tableau temporaire et renvoyer sa longueur.
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).
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é.
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é.
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;)
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.
Pour ceux qui ont Underscore.js inclus dans leur projet, vous pouvez faire:
_({a:'', b:''}).size() // => 2
ou style fonctionnel:
_.size({a:'', b:''}) // => 2
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.
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];
}
}
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.
Vous pouvez utiliser Object.keys(data).length
pour trouver la longueur d'un objet JSON contenant des données de clé.
Si jQuery ci-dessus ne fonctionne pas, essayez
$(Object.Item).length
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');
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.
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