Comment parcourir un objet JavaScript simple avec les objets en tant que membres?


1601

Comment puis-je parcourir tous les membres d'un objet JavaScript, y compris les valeurs qui sont des objets.

Par exemple, comment pourrais-je parcourir cela (en accédant à "votre_nom" et "votre_message" pour chacun)?

var validation_messages = {
    "key_1": {
        "your_name": "jimmy",
        "your_msg": "hello world"
    },
    "key_2": {
        "your_name": "billy",
        "your_msg": "foo equals bar"
    }
}

11
doublon possible de la boucle via un objet JavaScript
BuZZ-dEE

Réponses:


2115
for (var key in validation_messages) {
    // skip loop if the property is from prototype
    if (!validation_messages.hasOwnProperty(key)) continue;

    var obj = validation_messages[key];
    for (var prop in obj) {
        // skip loop if the property is from prototype
        if (!obj.hasOwnProperty(prop)) continue;

        // your code
        alert(prop + " = " + obj[prop]);
    }
}

13
Internet Explorer n'est pas d'accord ( soupir ), dit "L'objet ne prend pas en charge cette propriété ou méthode" lorsque vous faites obj [prop]. Je n'ai pas encore trouvé de solution à cela.
user999717

2
@MildFuzz en fait, cela a du sens si vous considérez que les objets JS n'ont pas nécessairement de touches numériques. Vous ne pouvez pas simplement parcourir un objet. JS for inest très similaire à un traditionnel foreach.
Jake Wilson

4
for ... in est une bonne solution, mais si vous utilisez des promesses dans la boucle for () - soyez prudent, car si vous créez un var dans la boucle, vous ne pouvez pas l'utiliser dans la fonction then de la promesse. Vous var dans la boucle n'existe qu'une seule fois, donc il a dans chaque fonction alors la même, même la dernière valeur. Si vous rencontrez ce problème, essayez «Object.keys (obj) .forEach» ou ma réponse ci-dessous.
Biber

hasOwnProperty est presque toujours redondant pour les navigateurs modernes (IE9 +).
Filyus Il y a

775

Sous ECMAScript 5, vous pouvez combiner Object.keys()et Array.prototype.forEach():

var obj = {
  first: "John",
  last: "Doe"
};

//
//	Visit non-inherited enumerable keys
//
Object.keys(obj).forEach(function(key) {

  console.log(key, obj[key]);

});


34
+1 pour la brièveté du code mais apparemment, ne fonctionne pas aussi efficacement que pour étonnamment. JSPerf - for in vs Object.keys
techiev2

6
Méfiez-vous de cette erreur en utilisant cette approche: "TypeError: Object.keys appelé sur un non-objet". Le for ... in ... hasOwnPropertymodèle peut être appelé sur n'importe quoi, pour autant que je sache (objet, tableau, null, non défini, vrai, faux, primitif numérique, objets).
theazureshadow

2
Notez qu'IE7 ne prend pas en charge cela.
Paul D. Waite

3
@ techiev2 ces tests n'ont jamais été valides. Voir mes mises à jour pour l'état actuel des performances: jsperf.com/objdir/20
OrganicPanda

4
@ techiev2: ce n'est pas Object.keys()ce qui le ralentit, c'est plutôt le forEach()et l'accès répété à .length! Si vous utilisez un for-loop classique à la place, c'est presque deux fois plus rapide que for..in+ hasOwnProperty()dans Firefox 33.
CodeManX

384

Le problème avec ça

for (var key in validation_messages) {
   var obj = validation_messages[key];
   for (var prop in obj) {
      alert(prop + " = " + obj[prop]);
   }
}

c'est que vous allez également parcourir le prototype de l'objet primitif.

Avec celui-ci vous l'éviterez:

for (var key in validation_messages) {
   if (validation_messages.hasOwnProperty(key)) {
      var obj = validation_messages[key];
      for (var prop in obj) {
         if (obj.hasOwnProperty(prop)) {
            alert(prop + " = " + obj[prop]);
         }
      }
   }
}

46
En bref: vérifiez hasOwnPropertydans vos for- inboucles.
Rory O'Kane

59
Notez que cela n'est nécessaire que si votre objet possède des méthodes de prototype. Par exemple, si l'objet que vous parcourez n'est qu'un objet JSON, vous n'aurez pas besoin de cette vérification.
gitaarik

6
@rednaw Pour être sûr, j'utilise cette vérification car Object.prototype peut être modifié. Aucun script sensé ne ferait cela, mais vous ne pouvez pas contrôler quels scripts peuvent être exécutés dans votre page par des extensions de navigateur insensées. Les extensions de navigateur s'exécutent sur votre page (sur la plupart des navigateurs) et peuvent provoquer des problèmes étranges (par exemple, définissez window.setTimeout sur null!).
robocat

1
Merci beaucoup
Blue Tram

328

Dans ES6 / 2015, vous pouvez parcourir un objet comme celui-ci: (en utilisant fonction flèche )

Object.keys(myObj).forEach(key => {
  console.log(key);        // the name of the current key.
  console.log(myObj[key]); // the value of the current key.
});

jsbin

Dans ES7 / 2016, vous pouvez utiliserObject.entries au lieu de Object.keyset parcourir un objet comme celui-ci:

Object.entries(myObj).forEach(([key, val]) => {
  console.log(key); // the name of the current key.
  console.log(val); // the value of the current key.
});

Ce qui précède fonctionnerait également comme une ligne :

Object.entries(myObj).forEach(([key, val]) => console.log(key, val));

jsbin

Si vous souhaitez également parcourir les objets imbriqués, vous pouvez utiliser une fonction récursive (ES6):

const loopNestedObj = obj => {
  Object.keys(obj).forEach(key => {
    if (obj[key] && typeof obj[key] === "object") loopNestedObj(obj[key]); // recurse.
    else console.log(key, obj[key]); // or do something with key and val.
  });
};

jsbin

Identique à la fonction ci-dessus, mais avec ES7 Object.entries() au lieu de Object.keys():

const loopNestedObj = obj => {
  Object.entries(obj).forEach(([key, val]) => {
    if (val && typeof val === "object") loopNestedObj(val); // recurse.
    else console.log(key, val); // or do something with key and val.
  });
};

Ici, nous parcourons les objets imbriqués pour modifier les valeurs et renvoyer un nouvel objet en une seule fois en Object.entries()combinaison avec Object.fromEntries()( ES10 / 2019 ):

const loopNestedObj = obj =>
  Object.fromEntries(
    Object.entries(obj).map(([key, val]) => {
      if (val && typeof val === "object") [key, loopNestedObj(val)]; // recurse
      else [key, updateMyVal(val)]; // or do something with key and val.
    })
  );

2
pour votre ES7 en utilisant l'exemple Object.entries, vous devez encapsuler les paramètres de la fonction de flèche [clé, val] entre parenthèses comme: `Object.entries (myObj) .forEach (([clé, val]) => {/ * instructions * /}
puiu

6
Je pense qu'il serait utile d'ajouter le fait que Object.entries et Object.keys n'itèrent pas sur le prototype, ce qui est la grande différence entre lui et la construction for in.
steviejay

Merci beaucoup
Blue Tram

95

Utilisation de Underscore.js_.each :

_.each(validation_messages, function(value, key){
    _.each(value, function(value, key){
        console.log(value);
    });
});

4
Merci Tim, utiliser le trait de soulignement est donc vraiment bon d'avoir une option rapide et propre.
The Coder

56

Si vous utilisez la récursivité, vous pouvez renvoyer des propriétés d'objet de n'importe quelle profondeur.

function lookdeep(object){
    var collection= [], index= 0, next, item;
    for(item in object){
        if(object.hasOwnProperty(item)){
            next= object[item];
            if(typeof next== 'object' && next!= null){
                collection[index++]= item +
                ':{ '+ lookdeep(next).join(', ')+'}';
            }
            else collection[index++]= [item+':'+String(next)];
        }
    }
    return collection;
}

//example

var O={
    a:1, b:2, c:{
        c1:3, c2:4, c3:{
            t:true, f:false
        }
    },
    d:11
};
var lookdeepSample= 'O={'+ lookdeep(O).join(',\n')+'}';


/*  returned value: (String)
O={
    a:1, 
    b:2, 
    c:{
        c1:3, c2:4, c3:{
            t:true, f:false
        }
    },
    d:11
}

*/

2
Méfiez-vous des boucles, comme appeler cela sur un nœud DOM.
theazureshadow

45

Cette réponse est un agrégat des solutions qui ont été fournies dans cet article avec quelques commentaires sur les performances . Je pense qu'il y a 2 cas d'utilisation et l'OP n'a pas mentionné s'il avait besoin d'accéder aux clés pour les utiliser pendant le processus de boucle.

I. les clés doivent être accessibles,

✔ l' approche ofetObject.keys

let k;
for (k of Object.keys(obj)) {

    /*        k : key
     *   obj[k] : value
     */
}

✔ l' inapproche

let k;
for (k in obj) {

    /*        k : key
     *   obj[k] : value
     */
}

Utilisez celui-ci avec prudence, car il pourrait imprimer les propriétés du prototype de obj

✔ l'approche ES7

for (const [key, value] of Object.entries(obj)) {

}

Cependant, au moment de l'édition, je ne recommanderais pas la méthode ES7, car JavaScript initialise beaucoup de variables en interne pour construire cette procédure (voir les retours pour preuve). À moins que vous ne développiez pas une énorme application qui mérite une optimisation, alors c'est ok mais si l'optimisation est votre priorité, vous devriez y penser.

II. nous avons juste besoin d'accéder à chaque valeur,

✔ l' approche ofetObject.values

let v;
for (v of Object.values(obj)) {

}

Plus de retours sur les tests:

  • La mise en cache Object.keysou les Object.valuesperformances sont négligeables

Par exemple,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
  • Par Object.valuesexemple, l'utilisation d'une forboucle native avec des variables mises en cache dans Firefox semble être un peu plus rapide que l'utilisation d'une for...ofboucle. Toutefois , la différence est pas si important et Chrome tourne for...ofplus vite que natif forboucle, donc je recommande d'utiliser for...oflorsqu'ils traitent avec Object.valuesdans tous les cas (4e et 6e essais).

  • Dans Firefox, la for...inboucle est vraiment lente, donc quand on veut mettre la clé en cache pendant l'itération il vaut mieux l'utiliser Object.keys. De plus, Chrome exécute les deux structures à vitesse égale (1er et dernier tests).

Vous pouvez vérifier les tests ici: https://jsperf.com/es7-and-misc-loops


2
L'exemple ES7 fonctionne comme un charme avec React Native!
Ty Bailey

Joliment expliqué. Merci
Alok Ranjan

30

Je sais qu'il est tard, mais il m'a fallu 2 minutes pour écrire cette version optimisée et améliorée de la réponse d'AgileJon:

var key, obj, prop, owns = Object.prototype.hasOwnProperty;

for (key in validation_messages ) {

    if (owns.call(validation_messages, key)) {

        obj = validation_messages[key];

        for (prop in obj ) {

            // using obj.hasOwnProperty might cause you headache if there is
            // obj.hasOwnProperty = function(){return false;}
            // but owns will always work 
            if (owns.call(obj, prop)) {
                console.log(prop, "=", obj[prop]);
            }

        }

    }

}

1
Pourquoi vous stockez hasOwnPropertydans owns, puis en appelant au owns.call(obj, prop)lieu de simplement appeler obj.hasOwnProperty(prop)que cette réponse fait?
Rory O'Kane

14
Parce objque la hasOwnPropertyfonction peut être définie sur elle-même, elle n'utilisera donc pas celle de Object.prototype. Vous pouvez essayer avant la forboucle comme ceci obj.hasOwnProperty = function(){return false;}et il n'itérera sur aucune propriété.
Azder

4
@Azder +1 pour la réponse et +1 si je le pouvais pour la bonne chose à propos d'Object.prototype.hasOwnProperty. J'ai déjà vu cela dans le code source de la bibliothèque de soulignement, mais je ne sais pas pourquoi.
Samuel

29
for(var k in validation_messages) {
    var o = validation_messages[k];
    do_something_with(o.your_name);
    do_something_else_with(o.your_msg);
}

14

p est la valeur

for (var key in p) {
  alert(key + ' => ' + p[key]);
}

OU

Object.keys(p).forEach(key => { console.log(key, p[key]) })

9

Dans ES7, vous pouvez faire:

for (const [key, value] of Object.entries(obj)) {
  //
}

J'ai fait quelques tests, cette méthode est vraiment lente lorsqu'il s'agit de grandes quantités de données.
vdegenne

8
for(var key in validation_messages){
    for(var subkey in validation_messages[key]){
        //code here
        //subkey being value, key being 'yourname' / 'yourmsg'
    }
}

7

Peu de façons de le faire ...

1) 2 couches pour ... en boucle ...

for (let key in validation_messages) {
   const vmKeys = validation_messages[key];
   for (let vmKey in vmKeys) {
      console.log(vmKey + vmKeys[vmKey]);
   }
}

2) UtilisationObject.key

Object.keys(validation_messages).forEach(key => {
   const vmKeys = validation_messages[key];
   Object.keys(vmKeys).forEach(key => {
    console.log(vmKeys + vmKeys[key]);
   });
});

3) Fonction récursive

const recursiveObj = obj => {
  for(let key in obj){
    if(!obj.hasOwnProperty(key)) continue;

    if(typeof obj[key] !== 'object'){
      console.log(key + obj[key]);
    } else {
      recursiveObj(obj[key]);
    }
  }
}

Et appelez-le comme:

recursiveObj(validation_messages);

5

Voici la version améliorée et récursive de la solution d'AgileJon ( démo ):

function loopThrough(obj){
  for(var key in obj){
    // skip loop if the property is from prototype
    if(!obj.hasOwnProperty(key)) continue;

    if(typeof obj[key] !== 'object'){
      //your code
      console.log(key+" = "+obj[key]);
    } else {
      loopThrough(obj[key]);
    }
  }
}
loopThrough(validation_messages);

Cette solution fonctionne pour toutes sortes de profondeurs différentes.


5

Une autre option:

var testObj = {test: true, test1: false};
for(let x of Object.keys(testObj)){
    console.log(x);
}

J'ai essayé votre solution dans Chrome 55.0 et vous obtenez une erreur de type. Votre réponse semble agréable et succincte, si vous pouvez la faire fonctionner, ce serait probablement l'une des meilleures options. J'ai essayé de le comprendre, mais je ne comprends pas votre solution.
TolMera

2
@TolMera Fixed.
mec

4

ECMAScript-2017, qui vient d'être finalisé il y a un mois, présente Object.values ​​(). Alors maintenant, vous pouvez le faire:

let v;
for (v of Object.values(validation_messages))
   console.log(v.your_name);   // jimmy billy

3

Je pense qu'il vaut la peine de souligner que jQuery trie bien avec $.each() .

Voir: https://api.jquery.com/each/

Par exemple:

$('.foo').each(function() {
    console.log($(this));
});

$(this)étant l'élément unique à l'intérieur de l'objet. Basculez $('.foo')vers une variable si vous ne souhaitez pas utiliser le moteur de sélection de jQuery.


3

var obj={
name:"SanD",
age:"27"
}
Object.keys(obj).forEach((key)=>console.log(key,obj[key]));

Pour parcourir un objet JavaScript, nous pouvons utiliser forEach et pour optimiser le code, nous pouvons utiliser la fonction flèche


2

Je n'ai pas pu obtenir les messages ci-dessus pour faire exactement ce que je cherchais.

Après avoir joué avec les autres réponses ici, je l'ai fait. C'est hacky, mais ça marche!

Pour cet objet:

var myObj = {
    pageURL    : "BLAH",
    emailBox   : {model:"emailAddress", selector:"#emailAddress"},
    passwordBox: {model:"password"    , selector:"#password"}
};

... ce code:

// Get every value in the object into a separate array item ...
function buildArray(p_MainObj, p_Name) {
    var variableList = [];
    var thisVar = "";
    var thisYes = false;
    for (var key in p_MainObj) {
       thisVar = p_Name + "." + key;
       thisYes = false;
       if (p_MainObj.hasOwnProperty(key)) {
          var obj = p_MainObj[key];
          for (var prop in obj) {
            var myregex = /^[0-9]*$/;
            if (myregex.exec(prop) != prop) {
                thisYes = true;
                variableList.push({item:thisVar + "." + prop,value:obj[prop]});
            }
          }
          if ( ! thisYes )
            variableList.push({item:thisVar,value:obj});
       }
    }
    return variableList;
}

// Get the object items into a simple array ...
var objectItems = buildArray(myObj, "myObj");

// Now use them / test them etc... as you need to!
for (var x=0; x < objectItems.length; ++x) {
    console.log(objectItems[x].item + " = " + objectItems[x].value);
}

... produit ceci dans la console:

myObj.pageURL = BLAH
myObj.emailBox.model = emailAddress
myObj.emailBox.selector = #emailAddress
myObj.passwordBox.model = password
myObj.passwordBox.selector = #password

0

La solution qui fonctionne pour moi est la suivante

_private.convertParams=function(params){
    var params= [];
    Object.keys(values).forEach(function(key) {
        params.push({"id":key,"option":"Igual","value":params[key].id})
    });
    return params;
}

0

Exotique - traversée profonde

JSON.stringify(validation_messages,(field,value)=>{
  if(!field) return value;

  // ... your code

  return value;
})

Dans cette solution, nous utilisons un remplaçant qui permet de parcourir en profondeur l'objet entier et les objets imbriqués - à chaque niveau, vous obtiendrez tous les champs et toutes les valeurs. Si vous devez obtenir le chemin d' accès complet à chaque champ, regardez ici


-6

Dans mon cas (sur la base de ce qui précède) est possible un certain nombre de niveaux.

var myObj = {
    rrr: undefined,
    pageURL    : "BLAH",
    emailBox   : {model:"emailAddress", selector:"#emailAddress"},
    passwordBox: {model:"password"    , selector:"#password"},
    proba: {odin:{dva:"rr",trr:"tyuuu"}, od:{ff:5,ppa:{ooo:{lll:'lll'}},tyt:'12345'}}
};


function lookdeep(obj,p_Name,gg){
    var A=[], tem, wrem=[], dd=gg?wrem:A;
    for(var p in obj){
        var y1=gg?'':p_Name, y1=y1 + '.' + p;
        if(obj.hasOwnProperty(p)){
           var tem=obj[p];
           if(tem && typeof tem=='object'){
               a1=arguments.callee(tem,p_Name,true);
               if(a1 && typeof a1=='object'){for(i in a1){dd.push(y1 + a1[i])};}
            }
            else{
               dd.push(y1 + ':' + String(tem));
            }
        }
    };
    return dd
};


var s=lookdeep(myObj,'myObj',false);
for (var x=0; x < s.length; ++x) {
console.log(s[x]+'\n');}

résultat:

["myObj.rrr:undefined",
"myObj.pageURL:BLAH",
"myObj.emailBox.model:emailAddress",
"myObj.emailBox.selector:#emailAddress",
"myObj.passwordBox.model:password",
"myObj.passwordBox.selector:#password",
"myObj.proba.odin.dva:rr",
"myObj.proba.odin.trr:tyuuu",
"myObj.proba.od.ff:5",
"myObj.proba.od.ppa.ooo.lll:lll",
"myObj.proba.od.tyt:12345"]
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.