Pregunta ¿Cómo recorrer un objeto JavaScript sin formato con los objetos como miembros?


¿Cómo puedo recorrer todos los miembros en un objeto 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"
    }
}

1243
2018-05-28 16:18


origen


Respuestas:


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

1797
2018-05-28 16:20



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

});


564
2018-04-20 22:04



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

363
2018-05-19 20:58



En ES6 puede recorrer un objeto como este: (usando 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 puedes usar Object.entries en lugar de Object.keys y 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 un un trazador de líneas:

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

jsbin

En caso de que desee pasar también por los objetos anidados, puede usar un recursivo función (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 Object.entries en 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.
  });
};

Si te gusta programación funcional puedes usar Object.keys/Object.entries enumerar el objeto, luego procesar los valores y luego usar reduce() para convertir de nuevo a un nuevo objeto.

const loopNestedObj = (obj) => 
  Object.keys(obj)
    // Use .filter(), .map(), etc. if you need.
    .reduce((newObj, key) => 
      (obj[key] && typeof obj[key] === 'object') ?
        {...newObj, [key]: loopNestedObj(obj[key])} :  // recurse.
        {...newObj, [key]: obj[key]},                  // Define value.
      {});

142
2018-01-09 14:22



Utilizando Underscore.js's _.each:

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

93
2017-09-16 12:11



Si usa la recursión puede devolver las propiedades del 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
}

*/

52
2018-05-28 18:03



Sé que ya fue tarde, pero tardé 2 minutos en 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]);
            }

        }

    }

}

29
2017-09-05 06:17



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

27
2018-05-28 16:20



Esta respuesta es un agregado de las soluciones que se proporcionaron en este   publicar con algunos actuación   retroalimentaciones. 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 llaves necesitan ser accedidas,

 el of y Object.keys enfoque

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

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

 el in enfoque

let k;
for (k in obj) {

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

Utilice este con cuidado, ya que podría imprimir las 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 construir este procedimiento (ver las evaluaciones para la prueba). A menos que no esté desarrollando una gran aplicación que merezca optimización, está bien, pero si la optimización es su prioridad, debería pensar en ello.

II. solo necesitamos acceder a cada valor,

 el of y Object.values enfoque

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

}

Más comentarios sobre las pruebas:

  • Almacenamiento en caché Object.keys o Object.values el rendimiento 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.values caso, usando un nativo for el bucle con variables en caché en Firefox parece ser un poco más rápido que usar un for...of lazo. Sin embargo, la diferencia no es tan importante y Chrome se está ejecutando for...of más rápido que nativo for loop, entonces yo recomendaría usar for...of cuando se trata de Object.values en cualquier caso (pruebas 4ta y 6ta).

  • En Firefox, el for...in el ciclo es muy lento, así que cuando queremos almacenar la clave durante la iteración, es mejor usar Object.keys. Además, Chrome está ejecutando ambas estructuras a la misma velocidad (primera y última prueba).

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


15
2017-09-24 03:34



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

8
2018-05-28 16:21



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

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.


5
2018-02-23 20:57