¿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"
    }
}

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

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

});


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

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

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

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
}

*/

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


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

        }

    }

}

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

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

9

En ES7 puedes hacer:

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

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

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

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.


5

Otra opción:

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

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

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.


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


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

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

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í


-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"]
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.