Come eseguire il loop attraverso un semplice oggetto JavaScript con gli oggetti come membri?


1601

Come posso scorrere tutti i membri in un oggetto JavaScript inclusi i valori che sono oggetti.

Ad esempio, come potrei scorrere questo (accedendo a "your_name" e "your_message" per ciascuno)?

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

Risposte:


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 non è d'accordo ( sospiro ), dice "L'oggetto non supporta questa proprietà o metodo" quando si fa obj [prop]. Devo ancora trovare una soluzione a questo.
user999717,

2
@MildFuzz in realtà ha senso se si considera che gli oggetti JS non hanno necessariamente tasti numerici. Non puoi semplicemente scorrere attraverso un oggetto. JS for inè molto simile a un tradizionale foreach.
Jake Wilson,

4
for ... in è una buona soluzione, ma se si usano le promesse nel ciclo for () - fare attenzione, perché se si crea una var nel ciclo, non è possibile utilizzarla nella funzione "promessa". Var nel ciclo esiste solo una volta, quindi ha in ogni funzione lo stesso, anche l'ultimo valore. Se hai questo problema, prova "Object.keys (obj) .forEach" o la mia risposta di seguito.
Biber,

hasOwnProperty è quasi sempre ridondante per i browser moderni (IE9 +).
Filyus

775

Sotto ECMAScript 5, puoi combinare Object.keys()e 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 per brevità del codice, ma a quanto pare, non funziona in modo sorprendente come per sorprendentemente. JSPerf - for in vs Object.keys
techiev2

6
Fai attenzione a questo errore usando questo approccio: "TypeError: Object.keys chiamato su non-oggetto". Il for ... in ... hasOwnPropertymodello può essere chiamato su qualsiasi cosa, per quanto posso dire (oggetto, matrice, null, indefinito, vero, falso, numero primitivo, oggetti).
theazureshadow

2
Si noti che IE7 non supporta questo.
Paul D. Waite,

3
@ techiev2 quei test non sono mai stati validi. Vedi quelli aggiornati per lo stato attuale delle prestazioni: jsperf.com/objdir/20
OrganicPanda

4
@ techiev2: non è Object.keys()ciò che lo rallenta, ma piuttosto l' forEach()accesso ripetuto a .length! Se invece usi un classico for-loop, è quasi due volte più veloce di for..in+ hasOwnProperty()in Firefox 33.
CodeManX

384

Il problema con questo

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

è che attraverserai anche il prototipo dell'oggetto primitivo.

Con questo lo eviterai:

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
In breve: controlla hasOwnPropertyall'interno dei tuoi for- inloop.
Rory O'Kane,

59
Nota che questo è necessario solo se il tuo oggetto HA metodi prototipo. Ad esempio, se l'oggetto che stai attraversando è solo un oggetto JSON, non avrai bisogno di questo controllo.
Gitaarik,

6
@rednaw Per sicurezza uso questo controllo perché Object.prototype può essere modificato. Nessuno script sano lo farebbe, ma non puoi controllare quali script potrebbero essere eseguiti nella tua pagina da estensioni del browser folli. Le estensioni del browser vengono eseguite nella tua pagina (sulla maggior parte dei browser) e possono causare strani problemi (ad es. Impostare window.setTimeout su null!).
robocat,

1
Grazie mille
Blue Tram,

328

In ES6 / 2015 puoi scorrere un oggetto in questo modo: (usando la funzione freccia )

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

In ES7 / 2016 è possibile utilizzare Object.entriesanziché Object.keyse scorrere un oggetto come questo:

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

Quanto sopra funzionerebbe anche come one-liner :

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

jsbin

Nel caso in cui si desideri eseguire anche il ciclo di oggetti nidificati, è possibile utilizzare una funzione ricorsiva (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

Come sopra, ma con ES7 Object.entries() invece di 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.
  });
};

Qui eseguiamo il ciclo tra gli oggetti nidificati modificando i valori e restituendo un nuovo oggetto in una sola volta usando in Object.entries()combinazione con 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
per il tuo ES7 usando l'esempio Object.entries, devi racchiudere i parametri della funzione freccia [chiave, val] tra parentesi come: `Object.entries (myObj) .forEach (([[key, val]) => {/ * istruzioni * /}
puiu

6
Penso che sarebbe utile aggiungere il fatto che Object.entries e Object.keys non eseguono l'iterazione sul prototipo, che è la grande differenza tra esso e il for nel costrutto.
Steviejay,

Grazie mille
Blue Tram,

95

Utilizzando Underscore.js_.each :

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

4
Grazie Tim, usando la sottolineatura è decisamente utile avere un'opzione rapida e pulita.
The Coder,

56

Se usi la ricorsione puoi restituire proprietà dell'oggetto di qualsiasi profondità-

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
Attenzione ai loop, come chiamare questo su un nodo DOM.
theazureshadow

45

Questa risposta è un aggregato delle soluzioni fornite in questo post con alcuni feedback sulle prestazioni . Penso che ci siano 2 casi d'uso e l'OP non ha menzionato se deve accedere alle chiavi per usarle durante il processo del ciclo.

I. è necessario accedere alle chiavi,

✔ l' approccio ofeObject.keys

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

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

✔ l' inapproccio

let k;
for (k in obj) {

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

Usa questo con cautela, in quanto potrebbe stampare proprietà prototipo di obj

✔ l'approccio ES7

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

}

Tuttavia, al momento della modifica non consiglierei il metodo ES7, perché JavaScript inizializza molte variabili internamente per creare questa procedura (vedere i feedback per la prova). A meno che tu non stia sviluppando un'app enorme che merita l'ottimizzazione, allora va bene ma se l'ottimizzazione è la tua priorità, dovresti pensarci.

II. dobbiamo solo accedere a ciascun valore,

✔ l' approccio ofeObject.values

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

}

Altri feedback sui test:

  • La memorizzazione nella cache Object.keyso le Object.valuesprestazioni sono trascurabili

Per esempio,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
  • Ad esempio Object.values, l'utilizzo di un forciclo nativo con variabili memorizzate nella cache in Firefox sembra essere un po 'più veloce rispetto all'utilizzo di un for...ofciclo. Tuttavia, la differenza non è così importante e Chrome è for...ofpiù veloce del forciclo nativo , quindi consiglierei di usarlo for...ofquando ci si occupa Object.valuesin tutti i casi (4 ° e 6 ° test).

  • In Firefox, il for...inciclo è molto lento, quindi quando vogliamo memorizzare il tasto nella cache durante l'iterazione è meglio usarlo Object.keys. Inoltre Chrome esegue entrambe le strutture alla stessa velocità (1 ° e ultimo test).

Puoi controllare i test qui: https://jsperf.com/es7-and-misc-loops


2
L'esempio ES7 funziona come un incantesimo con React Native!
Ty Bailey,

Ben spiegato. Grazie
Alok Ranjan

30

So che è tardi, ma mi ci sono voluti 2 minuti per scrivere questa versione ottimizzata e migliorata della risposta di 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
Perché si archiviano hasOwnPropertyin ownse quindi chiamando owns.call(obj, prop)invece di chiamare obj.hasOwnProperty(prop)come questa risposta fa?
Rory O'Kane,

14
Perché objpotrebbe avere la hasOwnPropertyfunzione definita su se stesso, quindi non utilizzerà quella da Object.prototype. Puoi provare prima del forciclo in questo modo obj.hasOwnProperty = function(){return false;}e non ripeterà alcuna proprietà.
Azder,

4
@Azder +1 per la risposta e +1 se potessi per la cosa bella di Object.prototype.hasOwnProperty. L'ho già visto nel codice sorgente della libreria di sottolineatura, ma non so perché.
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 è il valore

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

O

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

9

In ES7 puoi fare:

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

Ho fatto alcuni test, questo metodo è molto lento quando si tratta di grandi quantità di dati.
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

Pochi modi per farlo ...

1) 2 strati per ... in loop ...

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

2) UtilizzoObject.key

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

3) Funzione ricorsiva

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

E chiamalo come:

recursiveObj(validation_messages);

5

Ecco la versione migliorata e ricorsiva della soluzione di AgileJon ( demo ):

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

Questa soluzione funziona per tutti i tipi di profondità diverse.


5

Un'altra opzione:

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

Ho provato la tua soluzione in Chrome 55.0 e ricevi un errore di tipo. La tua risposta sembra piacevole e concisa, se riesci a farlo funzionare probabilmente sarebbe una delle opzioni migliori. Ho provato a immaginarlo ma non capisco la tua soluzione.
TolMera,

2
@TolMera Risolto.
amico,

4

ECMAScript-2017, appena finalizzato un mese fa, introduce Object.values ​​(). Quindi ora puoi farlo:

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

3

Penso che valga la pena sottolineare che jQuery risolve bene questo problema $.each().

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

Per esempio:

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

$(this)essendo il singolo oggetto all'interno dell'oggetto. Scambia $('.foo')su una variabile se non desideri utilizzare il motore di selezione di jQuery.


3

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

Per eseguire il ciclo attraverso JavaScript Object possiamo usare forEach e per ottimizzare il codice possiamo usare la funzione freccia


2

Non sono riuscito a ottenere i post sopra per fare esattamente quello che stavo cercando.

Dopo aver giocato con le altre risposte qui, l'ho fatto. È confuso, ma funziona!

Per questo oggetto:

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

... questo codice:

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

... produce questo nella console:

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

0

La soluzione che funziona per me è la seguente

_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

Uno esotico - traversata profonda

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

  // ... your code

  return value;
})

In questa soluzione utilizziamo il sostituto che consente di attraversare in profondità l'intero oggetto e gli oggetti nidificati: ad ogni livello otterrai tutti i campi e i valori. Se hai bisogno di ottenere il percorso completo per ogni campo, guarda qui


-6

Nel mio caso (sulla base del precedente) è possibile un numero qualsiasi di livelli.

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

risultato:

["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"]
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.