Iterar a través de las propiedades del objeto

2040

var obj = {
    name: "Simon",
    age: "20",
    clothing: {
        style: "simple",
        hipster: false
    }
}

for(var propt in obj){
    console.log(propt + ': ' + obj[propt]);
}

¿Cómo proptrepresenta la variable las propiedades del objeto? No es un método o propiedad incorporado. ¿Por qué aparece con todas las propiedades en el objeto?

Rafay
fuente
11
if (typeof(obj[propt]) === 'object') {/ * Hazlo de nuevo * /}
noob
13
Bueno, lamento mucho esta pregunta. Sé lo que es un bucle, no pude entender "recorrer las propiedades del objeto", lo que creo que ahora está despejado. Además, me han recomendado "JavaScript paso a paso, segunda edición - Steve Suehring en la escuela.
Rafay
242
Esta es una buena pregunta para principiantes. Agregaría que tengo 15 años de experiencia profesional con otros idiomas y necesitaba esta respuesta. Me gustaría más 2000 si pudiera.
Nathan C. Tresch
6060
Loco, pero he estado visitando esta página cada pocos meses durante años para volver a aprender la sintaxis sobre cómo hacer esto. No me molesto en recordar cómo hacer esto ... Solo recuerdo que esta página siempre está aquí en SO.
HDave
14
Esta es la página más extraña que he visto en StackOverflow. Si lee la pregunta detenidamente, solo una respuesta comenzará a intentar responder a lo que realmente se está preguntando, y tiene una puntuación de -6. La respuesta con la puntuación más alta, que fue aceptada, no solo no responde, sino que simplemente está equivocada.

Respuestas:

2426

Iterar sobre propiedades requiere esta hasOwnPropertyverificación adicional :

for (var prop in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, prop)) {
        // do stuff
    }
}

Es necesario porque el prototipo de un objeto contiene propiedades adicionales para el objeto que técnicamente son parte del objeto. Estas propiedades adicionales se heredan de la clase de objeto base, pero siguen siendo propiedades de obj.

hasOwnProperty simplemente verifica si esta es una propiedad específica de esta clase, y no una heredada de la clase base.


También es posible llamar a hasOwnPropertytravés del objeto en sí:

if (obj.hasOwnProperty(prop)) {
    // do stuff
}

Pero esto fallará si el objeto tiene un campo no relacionado con el mismo nombre:

var obj = { foo: 42, hasOwnProperty: 'lol' };
obj.hasOwnProperty('foo');  // TypeError: hasOwnProperty is not a function

Es por eso que es más seguro llamarlo Object.prototype:

var obj = { foo: 42, hasOwnProperty: 'lol' };
Object.prototype.hasOwnProperty.call(obj, 'foo');  // true
Hada lambda
fuente
21
@BT De acuerdo con la documentación de Mozilla : "Si solo desea considerar las propiedades adjuntas al objeto en sí, y no sus prototipos, use getOwnPropertyNames o realice una comprobación hasOwnProperty (también se puede usar propertyIsEnumerable)".
davidmdem
3
¿Cuál es exactamente el punto de llamar object.hasOwnProperty()? ¿El hecho de que propertytenga algún valor no implica que está dentro object?
Alex S
66
Porque, Alex S, el prototipo de un objeto contiene propiedades adicionales para el objeto que técnicamente son parte del objeto. Se heredan de la clase de objeto base, pero siguen siendo propiedades. hasOwnProperty simplemente verifica si esta es una propiedad específica de esta clase, y no una heredada de la clase base. Una buena explicación: brianflove.com/2013/09/05/javascripts-hasownproperty-method
Kyle Richter
87
Sin embargo, creo que debería mencionar que Object.keys (obj) es ahora una solución mucho mejor para obtener las claves del objeto en sí. Enlace a la documentación de Mozilla: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Kyle Richter
99
Falta una pieza importante de información. propertyes una cadena aquí, debería haberse llamado propertyName. De lo contrario, puede causar confusión a los novatos de JS como yo, es decir, qué hacer dentro del if.
Neolisk
1136

A partir de JavaScript 1.8.5, puede usar Object.keys(obj)para obtener una matriz de propiedades definidas en el objeto en sí (las que devuelven verdadero para obj.hasOwnProperty(key)).

Object.keys(obj).forEach(function(key,index) {
    // key: the name of the object key
    // index: the ordinal position of the key within the object 
});

Esto es mejor (y más legible) que usar un bucle for-in.

Es compatible con estos navegadores:

  • Firefox (Gecko): 4 (2.0)
  • Cromo: 5
  • Internet Explorer: 9

Consulte la referencia de Object.keys () de Mozilla Developer Network para obtener más información.

Danny R
fuente
77
Esto ahora es más ampliamente compatible: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Dom Vinyard
3
Y si necesita soporte para navegadores antiguos, puede usar este polyfill
KyleMit
27
En entornos que admiten esta construcción del lenguaje, este método permite llamar a Array.foreach: Object.keys(myObject).forEach(function(key,index) { //key = the name of the object key //index = the ordinal position of the key within the object });
Precio de Todd
44
@ AJ_83 No hay una buena manera de salir de forEach (). Use some () en este caso, y regrese true to break
Daniel Z.
11
¿Por qué es más legible que for-in? for candidate in candidateStatus... me parece legible
Jona
309

Chicas y chicos estamos en 2019 y no tenemos tanto tiempo para escribir ... Así que hagamos este nuevo e interesante ECMAScript 2016:

Object.keys(obj).forEach(e => console.log(`key=${e}  value=${obj[e]}`));
Frank Roth
fuente
17
¿Cómo es esto diferente a la respuesta de Danny R?
krillgar
27
Es un oneliner y usa un mapa en lugar de forEach. Y también el estado de console.log puede ser interesante para algunas personas.
Frank Roth
Satly, eso no funciona cuando obj=window.performance.memory: - / Donde como lo for inhace. es decirvar obj = window.performance.memory; for( key in obj ) console.log( 'key=' + key + ' val=' + obj[key] );
Michaelangel007
2
window.performance.memorysolo es compatible con Chrome y Object.keys(obj)devuelve una matriz vacía. Esto no tiene nada que ver con eso .map.
Frank Roth
En caso de que alguien no quiera evitar reestructurar este trazador de líneas para hacer más de una cosa a la vez e, he publicado esta idea. Básicamente es como la mayoría de las implementaciones de hash, y usa en ( (key) => (value) )lugar de { key => value }, pero si no ha tenido que lidiar con eso antes, podría ayudarlo a visualizarlo mejor: gist.github.com/the-nose-knows/9f06e745a56ff20519707433e28a4fa8
kayleeFrye_onDeck
216

Es la for...in statement( MDN , especificación ECMAScript ).

Puede leerlo como " PARA cada propiedad EN el objobjeto, asigne cada propiedad a la variable PROPT a su vez".

Marc B
fuente
1
Muchas gracias, lo entiendo ahora. Me estaba golpeando la cabeza, revisando libros y Google.
Rafay
21
De acuerdo con @RightSaidFred, el inoperador y la fordeclaración no están involucrados en absoluto, la for-inafirmación representa una producción gramatical en su propia: for ( LeftHandSideExpression in Expression ),for ( var VariableDeclarationNoIn in Expression )
CMS
2
Es extraño que esta respuesta tenga tantos votos positivos, especialmente porque estos comentarios populares parecen contradecirla.
Doug Molineux
99
¿Por qué está marcado como la respuesta? Es posiblemente el menos útil en este hilo ..
computrius
3
¿La respuesta menos útil? Depende de lo que creas que estaba preguntando el OP; Cuando leí la pregunta por primera vez, parecía desconcertado sobre el mecanismo por el cual una variable se puede utilizar para inspeccionar las propiedades de un objeto, y que esta respuesta explica de manera elocuente (a pesar del nombre inapropiado 'for-in'). La pregunta "¿Por qué aparece con todas las propiedades?" Que veo podría implicar que el OP estaba buscando hasOwnProperty pero no lo sabe, pero creo que es más probable que esto sea lo que el OP quería saber, y ha aceptado incorrectamente un correcto Responde a una pregunta diferente. :-)
Bumpy
157

En implementaciones actualizadas de ES, puede usar Object.entries:

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

o

Object.entries(obj).forEach(([key, value]) => ...)

Si solo desea iterar sobre los valores, use Object.values:

for (const value of Object.values(obj)) { }

o

Object.values(obj).forEach(value => ...)
OneHoopyFrood
fuente
Esta sería la mejor solución (object.entries ...), pero no puedo usarla. Cuando quiera hacer esto varias veces y no pueda admitirlo en su marco, puede usar el polyfill en esta página: developer.mozilla.org/nl/docs/Web/JavaScript/Reference/…
Mario
La tercera sugerencia es excelente si solo utiliza los valores de las propiedades. ¡Increíble!
Ginzburg
27

Si su entorno es compatible con ES2017 , recomendaría Object.entries :

Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key} ${value}`);
});

Como se muestra en la documentación de Object.entries () de Mozillas :

El método Object.entries () devuelve una matriz de pares de propiedad [clave, valor] enumerable de un objeto dado, en el mismo orden que el proporcionado por un bucle for ... in (la diferencia es que un bucle for-in enumera propiedades en la cadena del prototipo también).

Básicamente con Object.entries podemos renunciar al siguiente paso adicional que se requiere con el anterior para ... en bucle:

// This step is not necessary with Object.entries
if (object.hasOwnProperty(property)) {
  // do stuff
}
JSON C11
fuente
22

jquery te permite hacer esto ahora:

$.each( obj, function( key, value ) {
  alert( key + ": " + value );
});
Rob Sedgwick
fuente
1
$.each({foo:1, length:0, bar:2}, function(k,v){console.log(k,v)})$ .each no es adecuado para objetos. Si un objeto tiene una propiedad de longitud y su valor es cero, todo el objeto se trata como si fuera una matriz vacía.
Bob Stein
Detalla por qué creo que este es un enfoque de invitación de errores .
Bob Stein
21

La respuesta de Dominik es perfecta, solo prefiero hacerlo de esa manera, ya que es más claro de leer:

for (var property in object) {
    if (!object.hasOwnProperty(property)) continue;

    // Do stuff...
}
Cyril N.
fuente
Sin Objectembargo, debe estar en mayúscula o, ¿no?
Jonathan
18

Las respuestas anteriores son un poco molestas porque no explican lo que haces dentro del ciclo for después de asegurarte de que es un objeto: ¡NO LO ACCEDES DIRECTAMENTE! En realidad, solo se le entrega la CLAVE que debe aplicar al OBJ:

var obj = {
  a: "foo",
  b: "bar",
  c: "foobar"
};

// We need to iterate the string keys (not the objects)
for(var someKey in obj)
{
  // We check if this key exists in the obj
  if (obj.hasOwnProperty(someKey))
  {
    // someKey is only the KEY (string)! Use it to get the obj:
    var myActualPropFromObj = obj[someKey]; // Since dynamic, use [] since the key isn't literally named "someKey"

    // NOW you can treat it like an obj
    var shouldBeBar = myActualPropFromObj.b;
  }
}

Todo esto es seguro para ECMA5. Incluso funciona en las versiones JS cojo como Rhino;)

dylanh724
fuente
15

Para agregar el uso de ES2015 Reflect.ownKeys(obj)y también iterar sobre las propiedades a través de un iterador.

Por ejemplo:

let obj = { a: 'Carrot', b: 'Potato', Car: { doors: 4 } };

puede ser iterado por

// logs each key
Reflect.ownKeys(obj).forEach(key => console.log(key));

Si desea iterar directamente sobre los valores de las claves de un objeto, puede definir un iterator, al igual que los iteradores predeterminados de JavaScipts para cadenas, matrices, matrices escritas, Map y Set.

JS intentará iterar a través de la propiedad de iterador predeterminada, que debe definirse como Symbol.iterator.

Si desea poder iterar sobre todos los objetos, puede agregarlo como un prototipo de Objeto:

Object.prototype[Symbol.iterator] = function*() { 
    for(p of Reflect.ownKeys(this)){ yield this[p]; }
}

Esto le permitiría iterar sobre los valores de un objeto con un bucle for ... of, por ejemplo:

for(val of obj) { console.log('Value is:' + val ) }

Precaución : al escribir esta respuesta (junio de 2018), todos los demás navegadores, excepto IE, admiten generadores e for...ofiteración a través deSymbol.iterator

Dimitar Nikovski
fuente
Aunque en realidad no está respondiendo la pregunta del OP, esto fue muy útil para mí, todavía no sabía sobre Reflect.
Michiel
15
if(Object.keys(obj).length) {
    Object.keys(obj).forEach(key => {
        console.log("\n" + key + ": " + obj[key]);
    });
}

// *** Explanation line by line ***

// Explaining the bellow line
// It checks if obj has at least one property. Here is how:
// Object.keys(obj) will return an array with all keys in obj
// If there is no keys in obj, it will return empty array = []
// Then it will get it's length, if it has at least one element,
// it's bigger than 0 which evaluates to true and the bellow 
// code will be executed.
// Else means it's length = 0 which evaluates to false
// NOTE: you can use Object.hasOwnProperty() instead of Object.keys(obj).length
if(Object.keys(obj).length) {

    // Explaining the bellow line
    // Just like in the previous line, this returns an array with
    // all keys in obj (because if code execution got here, it means 
    // obj has keys.) 
    // Then just invoke built-in javascript forEach() to loop
    // over each key in returned array and calls a call back function 
    // on each array element (key), using ES6 arrow function (=>)
    // Or you can just use a normal function ((key) { blah blah }).
    Object.keys(obj).forEach(key => {

        // The bellow line prints out all keys with their 
        // respective value in obj.
        // key comes from the returned array in Object.keys(obj)
        // obj[key] returns the value of key in obj
        console.log("\n" + key + ": " + obj[key]);
    });
}
Fouad Boukredine
fuente
3
Hola, ¿podría agregar más información sobre su respuesta, proporcionar solo código no ayuda?
Nicolas
Hola @Nicolas. He agregado una explicación línea por línea al código. Avíseme si aún no está claro
Fouad Boukredine
1
Debido a que forEach omite los valores vacíos , creo que podría deshacerse del if y simplemente hacer Object.keys(obj).forEach(e => console.log(`key=${e} value=${obj[e]}`));como la respuesta de Frank Roth.
Darkproduct
12

El bucle for ... in representa cada propiedad de un objeto porque es como un bucle for. Definiste propt en el for ... in loop haciendo:

    for(var propt in obj){
alert(propt + ': ' + obj[propt]);
}

Un bucle for ... in itera a través de las propiedades enumerables de un objeto. Cualquier variable que defina, o ponga en el bucle for ... in, cambia cada vez que pasa a la siguiente propiedad que itera. La variable en el bucle for ... in itera a través de las claves, pero su valor es el valor de la clave. Por ejemplo:

    for(var propt in obj) {
      console.log(propt);//logs name
      console.log(obj[propt]);//logs "Simon"
    }

Puede ver cómo la variable difiere del valor de la variable. En contraste, un bucle for ... of hace lo contrario.

Espero que esto ayude.

Vappor Washmade
fuente
11
let obj = {"a": 3, "b": 2, "6": "a"}

Object.keys(obj).map((item) => {console.log("item", obj[item])})

// a
// 3
// 2
Philll_t
fuente
1
Como se menciona en otros comentarios, forEaches más apropiado aquí, ya que mapestá destinado a devolver una nueva matriz con los resultados de llamar al bloque de código en cada iteración. Pero solo estamos interesados ​​en los efectos secundarios de cada iteración, no en el valor de retorno, por lo tanto, no necesitamos esa nueva matriz que mapnos brinda.
Danny
11
Object.keys(obj).forEach(key =>
  console.log(`key=${key} value=${obj[key]}`)
);
Extraño compañero
fuente
10

Puedes usar Lodash. La documentación

var obj = {a: 1, b: 2, c: 3};
_.keys(obj).forEach(function (key) {
    ...
});
viktarpunko
fuente
10
¿Por qué demonios esta "respuesta" tiene 10 votos a favor? No responde completamente la pregunta. Estoy empezando a perder la fe en la inteligencia del desarrollador promedio de JS.
developerbmw
1
@developerbmw Entiendo que usar las funciones de ES6 es más correcto, pero respondí hace un año. Por favor, comparta sus pensamientos con nosotros cuando tenga un minuto.
viktarpunko
1
La idea es centrarse más en los métodos nativos, en lugar de sugerirle al usuario que agregue una biblioteca de 10000 líneas a su página. No me malinterpreten, me gusta usar Lodash, pero hay un momento y un lugar para eso y no es esto.
9

Su forciclo está iterando sobre todas las propiedades del objeto obj. proptse define en la primera línea de su bucle for. Es una cadena que es el nombre de una propiedad del objobjeto. En la primera iteración del bucle, proptsería "nombre".

arb
fuente
9

Los objetos en JavaScript son colecciones de propiedades y, por lo tanto, se pueden enlazar en una para cada declaración.

Debe pensar objcomo una colección de valores clave.


fuente
! con la importante diferencia de que estas 'listas de propiedades' pueden tener nombres como claves, mientras que las matrices JS normales solo pueden tener números como claves.
Qqwy
9

Hoy en día, puede convertir un objeto JS estándar en un objeto iterable simplemente agregando un método Symbol.iterator. Luego puede usar un for ofbucle y acceder a sus valores directamente o incluso puede usar un operador de propagación en el objeto también. Frio. Veamos cómo podemos hacerlo:

var o = {a:1,b:2,c:3},
    a = [];
o[Symbol.iterator] = function*(){
                       var ok = Object.keys(this);
                            i = 0;
                       while (i < ok.length) yield this[ok[i++]];
                     };
for (var value of o) console.log(value);
// or you can even do like
a = [...o];
console.log(a);

Redu
fuente
1
Una forma interesante de hacer eso. Gracias por el function*descubrimiento!
Benj
5

Si ejecuta Node , recomendaría:

Object.keys(obj).forEach((key, index) => {
    console.log(key);
});
Justin
fuente
5

Si bien la respuesta mejor calificada es correcta, aquí hay un caso de uso alternativo, es decir, si está iterando sobre un objeto y desea crear una matriz al final. Usar en .maplugar deforEach

const newObj = Object.keys(obj).map(el => {
    //ell will hold keys 
   // Getting the value of the keys should be as simple as obj[el]
})
iRohitBhatia
fuente
4

Añadiendo también la forma recursiva:

function iterate(obj) {
    // watch for objects we've already iterated so we won't end in endless cycle
    // for cases like var foo = {}; foo.bar = foo; iterate(foo);
    var walked = [];
    var stack = [{obj: obj, stack: ''}];
    while(stack.length > 0)
    {
        var item = stack.pop();
        var obj = item.obj;
        for (var property in obj) {
            if (obj.hasOwnProperty(property)) {
                if (typeof obj[property] == "object") {
                  // check if we haven't iterated through the reference yet
                  var alreadyFound = false;
                  for(var i = 0; i < walked.length; i++)
                  {
                    if (walked[i] === obj[property])
                    {
                      alreadyFound = true;
                      break;
                    }
                  }
                  // new object reference
                  if (!alreadyFound)
                  {
                    walked.push(obj[property]);
                    stack.push({obj: obj[property], stack: item.stack + '.' + property});
                  }
                }
                else
                {
                    console.log(item.stack + '.' + property + "=" + obj[property]);
                }
            }
        }
    }
}

Uso:

iterate({ foo: "foo", bar: { foo: "foo"} }); 
Ondrej Svejdar
fuente
1
@faiz - vea mis comentarios, es una protección contra quedarse atrapado en un bucle sin fin cuando recorre recurrentemente objetos que tienen referencias cíclicas
Ondrej Svejdar
3

Lo que hace..in loop es que crea una nueva variable (var someVariable) y luego almacena cada propiedad del objeto dado en esta nueva variable (someVariable) una por una. Por lo tanto, si usa el bloque {}, puede iterar. Considere el siguiente ejemplo.

var obj = {
     name:'raman',
     hobby:'coding',
     planet:'earth'
     };

for(var someVariable in obj) {
  //do nothing..
}

console.log(someVariable); // outputs planet
Raman Sohi
fuente
Votar esto, dada su simplicidad. En mi caso de uso, necesito verificar todos los atributos en un objeto para valores dudosos: NaNs, nulos, indefinidos (eran puntos en un gráfico y estos valores impidieron que el gráfico se dibujara). Para obtener el valor en lugar del nombre, en el bucle que haría obj[someVariable]. Quizás la razón por la que se rechazó tanto es porque no es recursivo. Por lo tanto, esta no sería una solución adecuada si tiene un objeto altamente estructurado.
Katharine Osborne
@KatharineOsborne o tal vez es porque la siguiente frase es un poco críptica: "Por lo tanto, si usa el bloque {}, puede iterar". El código dice más que el texto.
bvdb
3

Aquí estoy iterando cada nodo y creando nombres de nodo significativos. Si nota, instanceOf Array e instanceOf Object prácticamente hace lo mismo (en mi aplicación, estoy dando una lógica diferente)

function iterate(obj,parent_node) {
    parent_node = parent_node || '';
    for (var property in obj) {
        if (obj.hasOwnProperty(property)) {
            var node = parent_node + "/" + property;
            if(obj[property] instanceof Array) {
                //console.log('array: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            } else if(obj[property] instanceof Object){
                //console.log('Object: ' + node + ":" + obj[property]);
                iterate(obj[property],node)
            }
            else {
                console.log(node + ":" + obj[property]);
            }
        }
    }
}

nota - Me inspira la respuesta de Ondrej Svejdar. Pero esta solución tiene un mejor rendimiento y es menos ambigua.

Faiz Mohamed Haneef
fuente
3

Básicamente, desea recorrer cada propiedad en el objeto.

JSFiddle

var Dictionary = {
  If: {
    you: {
      can: '',
      make: ''
    },
    sense: ''
  },
  of: {
    the: {
      sentence: {
        it: '',
        worked: ''
      }
    }
  }
};

function Iterate(obj) {
  for (prop in obj) {
    if (obj.hasOwnProperty(prop) && isNaN(prop)) {
      console.log(prop + ': ' + obj[prop]);
      Iterate(obj[prop]);
    }
  }
}
Iterate(Dictionary);
HovyTech
fuente
obj(prop)<- TypeError: obj no es una función
le_m
@le_m mi mal. Debo sacar accidentalmente el hasOwnPropertyatributo. Debería funcionar ahora.
HovyTech
2

Quiero agregar a las respuestas anteriores, porque es posible que tenga diferentes intenciones de Javascript. Un objeto JSON y un objeto Javascript son cosas diferentes, y es posible que desee recorrer las propiedades de un objeto JSON utilizando las soluciones propuestas anteriormente, y luego sorprenderse.

Suponga que tiene un objeto JSON como:

var example = {
    "prop1": "value1",
    "prop2": [ "value2_0", value2_1"],
    "prop3": {
         "prop3_1": "value3_1"
    }
}

La forma incorrecta de iterar a través de sus 'propiedades':

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        recursivelyIterateProperties(jsonObject[prop]);
    }
}

Puede que se sorprenda de ver la conexión de la consola 0, 1etc. cuando se repite a través de las propiedades de prop1y prop2y de prop3_1. Esos objetos son secuencias, y los índices de una secuencia son propiedades de ese objeto en Javascript.

Una mejor manera de iterar recursivamente a través de las propiedades de un objeto JSON sería verificar primero si ese objeto es una secuencia o no:

function recursivelyIterateProperties(jsonObject) {
    for (var prop in Object.keys(example)) {
        console.log(prop);
        if (!(typeof(jsonObject[prop]) === 'string')
            && !(jsonObject[prop] instanceof Array)) {
                recursivelyIterateProperties(jsonObject[prop]);

            }

     }
}
Jadiel de Armas
fuente
1

Para refinar aún más la respuesta aceptada, vale la pena señalar que si crea una instancia del objeto con un, var object = Object.create(null)entonces object.hasOwnProperty(property)activará un TypeError. Entonces, para estar seguro, deberías llamarlo desde el prototipo de esta manera:

for (var property in object) {
    if (Object.prototype.hasOwnProperty.call(object, property)) {
        // do stuff
    }
}
Konrad Kiss
fuente