¿Cómo recorrer un objeto JavaScript simple con los objetos como miembros?

1601

¿Cómo puedo recorrer todos los miembros en un objeto de JavaScript, incluidos los valores que son objetos?

Por ejemplo, ¿cómo podría recorrer esto (accediendo a "your_name" y "your_message" para cada uno)?

var validation_messages = {
    "key_1": {
        "your_name": "jimmy",
        "your_msg": "hello world"
    },
    "key_2": {
        "your_name": "billy",
        "your_msg": "foo equals bar"
    }
}
EDT
fuente
11
posible duplicado de Loop a través del objeto JavaScript
BuZZ-dEE

Respuestas:

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]);
    }
}
AgileJon
fuente
13
Internet Explorer no está de acuerdo ( suspiro ), dice "El objeto no admite esta propiedad o método" cuando haces obj [prop]. Todavía tengo que encontrar una solución a esto.
user999717
2
@MildFuzz en realidad tiene sentido si considera que los objetos JS no necesariamente tienen claves numéricas. No puede simplemente iterar a través de un objeto. JS for ines muy similar a un tradicional foreach.
Jake Wilson
44
for ... in es una buena solución, pero si usa promesas en el bucle for (), tenga cuidado, porque si crea una var en el bucle, no puede usarla en la función de promesa de entonces. Su var en el bucle existe solo una vez, por lo que tiene en cada función la misma, incluso el último valor. Si tienes ese problema, prueba "Object.keys (obj) .forEach" o mi respuesta a continuación.
Biber
hasOwnProperty es casi siempre redundante para los navegadores modernos (IE9 +).
Filyus hace
775

En ECMAScript 5, puede combinar Object.keys()y 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]);

});

Axel Rauschmayer
fuente
34
+1 por brevedad del código, pero aparentemente no funciona tan eficientemente como sorprendentemente. JSPerf - para in vs Object.keys
techiev2
66
Tenga cuidado con este error utilizando este enfoque: "TypeError: Object.keys llamado en no-objeto". El for ... in ... hasOwnPropertypatrón se puede invocar en cualquier cosa, por lo que puedo decir (objeto, matriz, nulo, indefinido, verdadero, falso, número primitivo, objetos).
theazureshadow
2
Tenga en cuenta que IE7 no es compatible con esto.
Paul D. Waite
3
@ techiev2 esas pruebas nunca fueron válidas. Vea mis actualizados para conocer el estado actual del rendimiento: jsperf.com/objdir/20
OrganicPanda
44
@ techiev2: ¡no es lo Object.keys()que lo hace lento, es más bien el forEach()acceso repetido .length! Si utiliza un clásico for-loop, es casi el doble de rápido que for..in+ hasOwnProperty()en Firefox 33.
CodeManX
384

El problema con esto

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

es que también recorrerás el prototipo del objeto primitivo.

Con este lo evitarás:

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]);
         }
      }
   }
}
Chango
fuente
46
En pocas palabras: comprobar hasOwnPropertyel interior de sus for- inbucles.
Rory O'Kane
59
Tenga en cuenta que esto solo es necesario si su objeto TIENE métodos prototipo. Por ejemplo, si el objeto que está recorriendo es solo un objeto JSON, no necesitará esta verificación.
gitaarik
66
@rednaw Para estar seguro, uso esa verificación porque Object.prototype se puede modificar. Ninguna secuencia de comandos sensata haría eso, pero no puede controlar qué secuencias de comandos pueden ejecutarse en su página mediante extensiones de navegador insanas. Las extensiones del navegador se ejecutan en su página (en la mayoría de los navegadores) y pueden causar problemas extraños (por ejemplo, establecer window.setTimeout en nulo).
robocat
1
Muchas gracias
Blue Tram
328

En ES6 / 2015 puede recorrer un objeto como este: (usando la función de flecha )

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

En ES7 / 2016 puede usar en Object.entrieslugar de Object.keysy recorrer un objeto como este:

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

Lo anterior también funcionaría como una línea :

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

jsbin

En caso de que también desee recorrer objetos anidados, puede usar una función recursiva (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

Igual que la función anterior, pero con ES7 en Object.entries() lugar 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.
  });
};

Aquí recorremos los valores anidados de los objetos anidados y devolveremos un nuevo objeto de una vez usando Object.entries()combinado 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.
    })
  );
Rotareti
fuente
2
para su ES7 usando el ejemplo Object.entries, necesita ajustar los parámetros de la función de flecha [key, val] entre paréntesis como: `Object.entries (myObj) .forEach (([key, val]) => {/ * declaraciones * /}
puiu
66
Creo que sería útil agregar el hecho de que Object.entries y Object.keys no iteran sobre el prototipo, que es la gran diferencia entre él y el for in construct.
steviejay
Muchas gracias
Blue Tram
95

Usando Underscore.js_.each :

_.each(validation_messages, function(value, key){
    _.each(value, function(value, key){
        console.log(value);
    });
});
Tim Santeford
fuente
44
Gracias Tim, usar subrayado es definitivamente bueno para tener una opción rápida y limpia.
The Coder
56

Si usa la recursión, puede devolver propiedades de objeto de cualquier profundidad.

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
}

*/
Kennebec
fuente
2
Tenga cuidado con los bucles, como llamar a esto en un nodo DOM.
theazureshadow
45

Esta respuesta es un agregado de las soluciones que se proporcionaron en esta publicación con algunos comentarios de rendimiento . Creo que hay 2 casos de uso y el OP no mencionó si necesita acceder a las claves para usarlas durante el proceso de bucle.

I. las claves deben ser accedidas,

✔ el ofy Object.keysenfoque

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

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

✔ el inenfoque

let k;
for (k in obj) {

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

Use este con precaución, ya que podría imprimir propiedades prototipo de obj

✔ el enfoque ES7

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

}

Sin embargo, en el momento de la edición, no recomendaría el método ES7, porque JavaScript inicializa muchas variables internamente para crear este procedimiento (consulte las evaluaciones para obtener una prueba). A menos que no esté desarrollando una aplicación enorme que merezca optimización, entonces está bien, pero si la optimización es su prioridad, debe pensar en ello.

II solo necesitamos acceder a cada valor,

✔ el ofy Object.valuesenfoque

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

}

Más comentarios sobre las pruebas:

  • El almacenamiento en caché Object.keyso el Object.valuesrendimiento es insignificante

Por ejemplo,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
  • Por Object.valuesejemplo, usar un forbucle nativo con variables en caché en Firefox parece ser un poco más rápido que usar un for...ofbucle. Sin embargo la diferencia no es tan importante y Chrome se ejecuta for...ofmás rápido que el nativo forde bucle, por lo que recomiendo para su uso for...ofcuando se trata de Object.values, en algún caso (4 y 6 pruebas).

  • En Firefox, el for...inciclo es realmente lento, por lo que cuando queremos almacenar en caché la clave durante la iteración, es mejor usarla Object.keys. Además, Chrome ejecuta ambas estructuras a la misma velocidad (primera y última prueba).

Puede consultar las pruebas aquí: https://jsperf.com/es7-and-misc-loops

vdegenne
fuente
2
¡El ejemplo ES7 funciona como un encanto con React Native!
Ty Bailey
Bien explicado. Gracias
Alok Ranjan
30

Sé que es muy tarde, pero me tomó 2 minutos escribir esta versión optimizada y mejorada de la respuesta de 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]);
            }

        }

    }

}
Azder
fuente
1
¿Por qué están almacenando hasOwnPropertyen ownsy después de llamar owns.call(obj, prop)en lugar de simplemente llamando obj.hasOwnProperty(prop)como esta respuesta hace?
Rory O'Kane
14
Porque objpodría tener la hasOwnPropertyfunción definida en sí misma, por lo que no utilizará la de Object.prototype. Puede probar antes del forbucle como este obj.hasOwnProperty = function(){return false;}y no iterará sobre ninguna propiedad.
Azder
44
@Azder +1 por la respuesta y +1 si pudiera por lo bueno de Object.prototype.hasOwnProperty. Lo vi anteriormente dentro del código fuente de la biblioteca de subrayado, pero no sé por qué.
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);
}
caos
fuente
14

p es el valor

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

O

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

En ES7 puedes hacer:

for (const [key, value] of Object.entries(obj)) {
  //
}
Kévin Berthommier
fuente
Hice algunas pruebas, este método es realmente lento cuando se trata de una gran cantidad de datos.
vdegenne
8
for(var key in validation_messages){
    for(var subkey in validation_messages[key]){
        //code here
        //subkey being value, key being 'yourname' / 'yourmsg'
    }
}
Dmitri Farkov
fuente
7

Pocas maneras de hacer eso ...

1) 2 capas para ... en bucle ...

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

2) UsandoObject.key

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

3) función recursiva

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

Y llámalo así:

recursiveObj(validation_messages);
Alireza
fuente
5

Aquí viene la versión mejorada y recursiva de la solución ( demostración ) de AgileJon :

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

Esta solución funciona para todo tipo de profundidades diferentes.

JepZ
fuente
5

Otra opción:

var testObj = {test: true, test1: false};
for(let x of Object.keys(testObj)){
    console.log(x);
}
tipo
fuente
Probé su solución en Chrome 55.0 y aparece un error de tipo. Su respuesta se ve agradable y sucinta, si puede hacer que funcione, probablemente sea una de las mejores opciones. Traté de resolverlo pero no entiendo tu solución.
TolMera
2
@TolMera fijo.
amigo
4

ECMAScript-2017, recién finalizado hace un mes, presenta Object.values ​​(). Entonces ahora puedes hacer esto:

let v;
for (v of Object.values(validation_messages))
   console.log(v.your_name);   // jimmy billy
Chong Lip Phang
fuente
3

Creo que vale la pena señalar que jQuery soluciona esto muy bien con $.each() .

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

Por ejemplo:

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

$(this)siendo el único elemento dentro del objeto. Cambie $('.foo')a una variable si no desea utilizar el motor de selección de jQuery.

Daniel Dewhurst
fuente
3

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

Para recorrer el objeto JavaScript podemos usar forEach y para optimizar el código podemos usar la función de flecha

Sandip Bailkar
fuente
2

No pude hacer que las publicaciones anteriores hicieran lo que buscaba.

Después de jugar con las otras respuestas aquí, hice esto. ¡Es hacky, pero funciona!

Para este objeto:

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

... este código:

// 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 esto en la consola:

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

La solución que funciona para mí es la siguiente

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

Uno exótico: recorrido profundo

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

  // ... your code

  return value;
})

En esta solución, utilizamos un sustituto que permite atravesar en profundidad objetos completos y objetos anidados; en cada nivel obtendrá todos los campos y valores. Si necesita obtener la ruta completa a cada campo, vea aquí

Kamil Kiełczewski
fuente
-6

En mi caso (sobre la base de lo anterior) es posible cualquier cantidad de niveles.

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

resultado:

["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"]
usuario2515312
fuente