Comment lister les propriétés d'un objet JavaScript?

842

Disons que je crée un objet ainsi:

var myObject =
        {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"};

Quelle est la meilleure façon de récupérer une liste des noms de propriété? c'est-à-dire que je voudrais me retrouver avec des "clés" variables telles que:

keys == ["ircEvent", "method", "regex"]
johnstok
la source
3
Un peu hors sujet, mais si vous utilisez underscore.js:_.keys(myJSONObject)
Endy Tjahjono

Réponses:

1076

Dans les navigateurs modernes (IE9 +, FF4 +, Chrome5 +, Opera12 +, Safari5 +), vous pouvez utiliser la méthode Object.keys intégrée :

var keys = Object.keys(myObject);

Ce qui précède a un polyfill complet mais une version simplifiée est:

var getKeys = function(obj){
   var keys = [];
   for(var key in obj){
      keys.push(key);
   }
   return keys;
}

Remplacez également var getKeyspar Object.prototype.keyspour vous permettre d'appeler .keys()n'importe quel objet. L'extension du prototype a des effets secondaires et je ne recommanderais pas de le faire.

slashnick
la source
17
Je mettrais à jour à nouveau l'effet "vous pourriez être tenté de le faire pour protester contre un objet ... mais ne le faites pas!"
AnthonyWJones
4
est-ce que quelqu'un voudra mettre la lumière dessus, pourquoi n'est-il pas recommandé d'ajouter des fonctions au prototype d'Object?
Vishwanath
2
C'est une toute autre question en soi, une recherche rapide ici sur stackoverflow ou sur google vous donnera beaucoup à lire
ximi
3
La for (var key in myObject) {...}technique est utile pour les exécutions javascript en dehors des navigateurs et V8. Par exemple, lors du passage de requêtes javascript map-reduction dans Riak, l' Objectobjet n'existe pas, donc la Object.keysméthode n'est pas disponible.
ekillaby
19
@slashnick Votre "version simplifiée" renvoie toutes les propriétés de la chaîne de prototypes de l'objet (car elle utilise un "pour ... dans"), tandis que la Object.keysméthode (ECMAScript 5.1) ne renvoie que les propres propriétés de l'objet. Je le vois comme une distinction importante.
Martin Carel
255

Comme l'a souligné slashnick , vous pouvez utiliser la construction "for in" pour parcourir un objet pour ses noms d'attribut. Cependant, vous itérerez sur tous les noms d'attributs de la chaîne de prototypes de l'objet. Si vous souhaitez itérer uniquement sur les propres attributs de l'objet, vous pouvez utiliser la méthode Object # hasOwnProperty () . Ayant ainsi les éléments suivants.

for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        /* useful code here */
    }
}
Pablo Cabrera
la source
25
J'aimerais avoir lu ceci avant la réponse de slashnic ci-dessus. J'ai juste dû passer 15 minutes à maintenir la escclé enfoncée car l'objet avait environ un million de propriétés, la plupart d'entre elles non utilisées, et j'avais une alerte à ce sujet.
Mark Henderson
Voici un excellent article sur le sujet par Zakas lui-même: nczonline.net/blog/2010/07/27/…
Pablo Cabrera
4
LOL @MarkHenderson - mais la prochaine fois, il suffit de tuer le processus du navigateur et de le redémarrer au lieu de perdre 15 minutes :)
JD Smith
Une fonction connexe est obj.getOwnPropertyNames () - developer.mozilla.org/en-US/docs/JavaScript/Reference/…
Steve Goodman
@MarkHenderson Pourquoi n'utiliserez-vous pas console.log?
LasagnaAndroid
102

Comme Sam Dutton a répondu, une nouvelle méthode à cet effet a été introduite dans ECMAScript 5e édition. Object.keys()fera ce que vous voulez et est pris en charge dans Firefox 4 , Chrome 6, Safari 5 et IE 9 .

Vous pouvez également implémenter très facilement la méthode dans les navigateurs qui ne la prennent pas en charge. Cependant, certaines implémentations ne sont pas entièrement compatibles avec Internet Explorer. Voici une solution plus compatible:

Object.keys = Object.keys || (function () {
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !{toString:null}.propertyIsEnumerable("toString"),
        DontEnums = [ 
            'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty',
            'isPrototypeOf', 'propertyIsEnumerable', 'constructor'
        ],
        DontEnumsLength = DontEnums.length;

    return function (o) {
        if (typeof o != "object" && typeof o != "function" || o === null)
            throw new TypeError("Object.keys called on a non-object");

        var result = [];
        for (var name in o) {
            if (hasOwnProperty.call(o, name))
                result.push(name);
        }

        if (hasDontEnumBug) {
            for (var i = 0; i < DontEnumsLength; i++) {
                if (hasOwnProperty.call(o, DontEnums[i]))
                    result.push(DontEnums[i]);
            }   
        }

        return result;
    };
})();

Notez que la réponse actuellement acceptée n'inclut pas une vérification de hasOwnProperty () et renverra des propriétés héritées de la chaîne de prototype. Il ne prend pas non plus en compte le célèbre bogue DontEnum dans Internet Explorer où les propriétés non énumérables sur la chaîne de prototypes font en sorte que les propriétés déclarées localement avec le même nom héritent de leur attribut DontEnum.

L'implémentation d' Object.keys () vous donnera une solution plus robuste.

EDIT: suite à une récente discussion avec kangax , un contributeur bien connu de Prototype, j'ai implémenté la solution de contournement pour le bogue DontEnum basée sur le code de sa Object.forIn()fonction trouvée ici .

Andy E
la source
Excellente réponse, je pense que la réponse acceptée reste la solution précise la plus performante, en supposant qu'il s'agit toujours d'un dict JSON. C'est certainement celui à utiliser ailleurs.
David Snabel-Caunt du
1
@David Caunt: Merci :-) Malheureusement, la réponse acceptée tomberait toujours dans le bogue DontEnum et vous ne savez jamais quel objet JSON pourrait avoir une chaîne comme "valueOf" ou "constructeur" comme l'une de ses clés. Il réitérera également les extensions de Object.prototype. Il est souvent le cas, cependant, que le code plus court semble beaucoup plus attrayant que le code plus grand et plus robuste, mais le but de cette réponse est d'utiliser ECMAScript 5th Object.keys(), qui peut être implémenté dans les navigateurs qui ne le prennent pas en charge en utilisant ce code. La version native serait encore plus performante que cela.
Andy E
2
Très gentil, Andy :) Je voudrais juste rappeler - personne ne semble le mentionner dans ce fil - que ES5 Object.keysne renvoie qu'un tableau de chaînes correspondant aux propriétés énumérables d'un objet. Cela peut ne pas être crucial lorsque vous travaillez avec des objets natifs (définis par l'utilisateur), mais devrait être très visible avec les objets hôtes (bien que le comportement des objets hôtes non spécifiés soit une histoire distincte - douloureuse). Pour énumérer TOUTES les propriétés (y compris non énumérables), ES5 fournit Object.getOwnPropertyNames(voir son support dans ma table compat. - kangax.github.com/es5-compat-table )
kangax
2
J'ai intégré cette solution dans es5-shim github.com/kriskowal/es5-shim/blob/master/es5-shim.js#L390
Kris Kowal
2
Quelqu'un peut-il expliquer pourquoi cela est mis en œuvre comme Object.keys(stuff)et non stuff.keys()?
Blazemonger
32

Notez que Object.keys et d'autres méthodes ECMAScript 5 sont pris en charge par Firefox 4, Chrome 6, Safari 5, IE 9 et supérieur.

Par exemple:

var o = {"foo": 1, "bar": 2}; 
alert(Object.keys(o));

Tableau de compatibilité ECMAScript 5: http://kangax.github.com/es5-compat-table/

Description des nouvelles méthodes: http://markcaudill.com/index.php/2009/04/javascript-new-features-ecma5/

Sam Dutton
la source
Consultez également les touches () dans la console pour Chrome Dev Tools, Firebug, etc.
Sam Dutton
28

Object.getOwnPropertyNames(obj)

Cette fonction affiche également des propriétés non énumérables en plus de celles indiquées par Object.keys(obj).

Dans JS, chaque propriété a quelques propriétés, y compris un booléen enumerable.

En général, les propriétés non énumérables sont plus «internes» et moins souvent utilisées, mais il est parfois judicieux de les examiner pour voir ce qui se passe réellement.

Exemple:

var o = Object.create({base:0})
Object.defineProperty(o, 'yes', {enumerable: true})
Object.defineProperty(o, 'not', {enumerable: false})

console.log(Object.getOwnPropertyNames(o))
// [ 'yes', 'not' ]

console.log(Object.keys(o))
// [ 'yes' ]

for (var x in o)
    console.log(x)
// yes, base

Notez également comment:

  • Object.getOwnPropertyNameset Object.keys ne remontez pas la chaîne du prototype pour trouverbase
  • for in Est-ce que

Plus d'informations sur la chaîne de prototypes ici: https://stackoverflow.com/a/23877420/895245

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
16

Je suis un grand fan de la fonction de vidage.

http://ajaxian.com/archives/javascript-variable-dump-in-coldfusion texte alternatif

Mat
la source
1
+1 parce que je suis arrivé ici dans l'intention de construire quelque chose de similaire (bien que moins bon).
Camilo Martin
1
netgrow.com.au/assets/files/dump/dump.zip introuvable Comment puis-je télécharger le jump Javascript?
Kiquenet
@Kiquenet à chaque fois que je voulais construire quelque chose comme ça, je me contente de l'inspecteur d'objets normal, si vous voulez que le rendu soit en HTML, il y a des choses comme les modules npm . Franchement, ce qui m'a bloqué, c'est que je voulais quelque chose de mieux que ce qui est sur cette image, mais je n'ai jamais réussi à la conceptualiser. C'est merdique de parcourir les objets dans l'inspecteur, mais l'heuristique pour essayer de déduire du sens à partir d'objets arbitraires (par exemple, trier des tableaux d'objets dans des tableaux avec des colonnes) ne fonctionne pas toujours dans la pratique.
Camilo Martin
Qu'en est-il de Pretty Print Javascript https://j11y.io/demos/prettyprint/ ?
Kiquenet
13

Pourrait le faire avec jQuery comme suit:

var objectKeys = $.map(object, function(value, key) {
  return key;
});
sbonami
la source
9

si vous essayez d'obtenir uniquement les éléments mais pas les fonctions, ce code peut vous aider

this.getKeys = function() {

    var keys = new Array();
    for(var key in this) {

        if( typeof this[key] !== 'function') {

            keys.push(key);
        }
    }
    return keys;
}

cela fait partie de mon implémentation du HashMap et je veux seulement les clés, "ceci" est l'objet hashmap qui contient les clés

zeacuss
la source
8

Cela fonctionnera dans la plupart des navigateurs, même dans IE8, et aucune bibliothèque d'aucune sorte n'est requise. var i est votre clé.

var myJSONObject =  {"ircEvent": "PRIVMSG", "method": "newURI", "regex": "^http://.*"}; 
var keys=[];
for (var i in myJSONObject ) { keys.push(i); }
alert(keys);
qwerty_jones
la source
2
Votre réponse semble similaire à celles déjà publiées, autre chose à ajouter?
VKen
7

Sous les navigateurs prenant en charge js 1.8:

[i for(i in obj)]
Rix Beck
la source
7

Mozilla a des détails d'implémentation complets sur la façon de le faire dans un navigateur où il n'est pas pris en charge, si cela aide:

if (!Object.keys) {
  Object.keys = (function () {
    var hasOwnProperty = Object.prototype.hasOwnProperty,
        hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
        dontEnums = [
          'toString',
          'toLocaleString',
          'valueOf',
          'hasOwnProperty',
          'isPrototypeOf',
          'propertyIsEnumerable',
          'constructor'
        ],
        dontEnumsLength = dontEnums.length;

    return function (obj) {
      if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');

      var result = [];

      for (var prop in obj) {
        if (hasOwnProperty.call(obj, prop)) result.push(prop);
      }

      if (hasDontEnumBug) {
        for (var i=0; i < dontEnumsLength; i++) {
          if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
        }
      }
      return result;
    };
  })();
}

Vous pouvez l'inclure comme vous le souhaitez, mais éventuellement dans une sorte de extensions.jsfichier en haut de votre pile de scripts.

Kristofer Sommestad
la source
L'implémentation de MDN est basée sur Andy E, qui a déjà été donnée comme réponse.
Outis
5

Utilisation Reflect.ownKeys()

var obj = {a: 1, b: 2, c: 3};
Reflect.ownKeys(obj) // ["a", "b", "c"]

Object.keys et Object.getOwnPropertyNames ne peuvent pas obtenir de propriétés non énumérables . Cela fonctionne même pour les propriétés non énumérables .

var obj = {a: 1, b: 2, c: 3};
obj[Symbol()] = 4;
Reflect.ownKeys(obj) // ["a", "b", "c", Symbol()]
selmansamet
la source
4

Puisque j'utilise underscore.js dans presque tous les projets, j'utiliserais la keysfonction:

var obj = {name: 'gach', hello: 'world'};
console.log(_.keys(obj));

La sortie de cela sera:

['name', 'hello']
schmijos
la source
C'est une bibliothèque de
jeux d'
4

S'appuyant sur la réponse acceptée.

Si l'objet a des propriétés que vous voulez appeler, dites .properties () essayez!

var keys = Object.keys(myJSONObject);

for (var j=0; j < keys.length; j++) {
  Object[keys[j]].properties();
}
Sydwell
la source
0

La solution fonctionne sur mes coques et cross-browser:

var getKeys = function(obj) {
    var type = typeof  obj;
    var isObjectType = type === 'function' || type === 'object' || !!obj;

    // 1
    if(isObjectType) {
        return Object.keys(obj);
    }

    // 2
    var keys = [];
    for(var i in obj) {
        if(obj.hasOwnProperty(i)) {
            keys.push(i)
        }
    }
    if(keys.length) {
        return keys;
    }

    // 3 - bug for ie9 <
    var hasEnumbug = !{toString: null}.propertyIsEnumerable('toString');
    if(hasEnumbug) {
        var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
            'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];

        var nonEnumIdx = nonEnumerableProps.length;

        while (nonEnumIdx--) {
            var prop = nonEnumerableProps[nonEnumIdx];
            if (Object.prototype.hasOwnProperty.call(obj, prop)) {
                keys.push(prop);
            }
        }

    }

    return keys;
};
Christian Nguyen
la source