¿Cómo iterar sobre un objeto JavaScript?

422

Tengo un objeto en JavaScript:

{
    abc: '...',
    bca: '...',
    zzz: '...',
    xxx: '...',
    ccc: '...',
    // ...
}

Quiero usar un forbucle para obtener sus propiedades. Y quiero iterarlo en partes (no todas las propiedades del objeto a la vez).

Con una matriz simple, puedo hacerlo con un forbucle estándar :

for (i = 0; i < 100; i++) { ... } // first part
for (i = 100; i < 300; i++) { ... } // second
for (i = 300; i < arr.length; i++) { ... } // last

¿Pero cómo hacerlo con objetos?

nkuhta
fuente
22
Tenga en cuenta que las propiedades del objeto no se almacenan en orden. Cuando itera sobre un objeto, no hay garantía del orden en que aparecerán.
James Allardice

Respuestas:

851

Para la mayoría de los objetos, use for .. in:

for (let key in yourobject) {
  console.log(key, yourobject[key]);
}

Con ES6, si necesita claves y valores simultáneamente, haga

for (let [key, value] of Object.entries(yourobject)) {
    console.log(key, value);
}

Para evitar el registro de propiedades heredadas, verifique con hasOwnProperty :

for (let key in yourobject) {
   if (yourobject.hasOwnProperty(key)) {
      console.log(key, yourobject[key]);
   }
}

No necesita verificar hasOwnPropertyal iterar las teclas si está usando un objeto simple (por ejemplo, uno con el que se hizo {}).

Esta documentación de MDN explica de manera más general cómo tratar con objetos y sus propiedades.

Si desea hacerlo "en trozos", lo mejor es extraer las claves en una matriz. Como el pedido no está garantizado, esta es la forma correcta. En los navegadores modernos, puede usar

let keys = Object.keys(yourobject);

Para ser más compatible, será mejor que hagas esto:

 let keys = [];
 for (let key in yourobject) {      
     if (yourobject.hasOwnProperty(key)) keys.push(key);
 }

Luego puede iterar en sus propiedades por índice yourobject[keys[i]]:

for (let i=300; i < keys.length && i < 600; i++) { 
   console.log(keys[i], yourobject[keys[i]]);
}
Denys Séguret
fuente
3
OP quiere realizar esto en fragmentos, no todas las teclas en un solo bucle.
pawel
Si. Objeto no completo en un bucle.
nkuhta
2
@Cerbrus El OP ya sabe cómo iterar una matriz en partes. Usar keysdel código dado debería ser suficiente.
Yoshi
2
@Cerbrus ¡Por favor lea antes de comentar! ¿Qué no está claro en "Para ser más compatible, será mejor que hagas esto" ?
Denys Séguret
2
@ am05mhz Como dije, es inútil con la mayoría de los objetos. Pero no para todos. Pruebe esto: jsbin.com/hirivubuta/1/edit?js,console,output
Denys Séguret
61

Aquí hay otra solución de iteración para los navegadores modernos:

Object.keys(obj)
  .filter((k, i) => i >= 100 && i < 300)
  .forEach(k => console.log(obj[k]));

O sin la función de filtro:

Object.keys(obj).forEach((k, i) => {
    if (i >= 100 && i < 300) {
        console.log(obj[k]);
    }
});

Sin embargo, debe tener en cuenta que las propiedades en el objeto JavaScript no están ordenadas, es decir, no tienen orden.

Visión
fuente
Si voy a romper el bucle, comenzará desde el principio del objeto la próxima vez, eso no es lo correcto.
nkuhta
21

Usando Object.entrieshaces algo como esto.

 // array like object with random key ordering
 const anObj = { 100: 'a', 2: 'b', 7: 'c' };
 console.log(Object.entries(anObj)); // [ ['2', 'b'],['7', 'c'],['100', 'a'] ]

El método Object.entries () devuelve una matriz de la propiedad enumerable de un objeto dado [clave, valor]

Por lo tanto, puede iterar sobre el Objeto y tener keyy valuepara cada objeto y obtener algo como esto.

const anObj = { 100: 'a', 2: 'b', 7: 'c' };
Object.entries(anObj).map(obj => {
   const key   = obj[0];
   const value = obj[1];

   // do whatever you want with those values.
});

o así

// Or, using array extras
Object.entries(obj).forEach(([key, value]) => {
  console.log(`${key} ${value}`); // "a 5", "b 7", "c 9"
});

Para una referencia, eche un vistazo a los documentos MDN para entradas de objeto

Adeel Imran
fuente
18

Con las nuevas características ES6 / ES2015, ya no tiene que usar un objeto para iterar sobre un hash. Puedes usar un mapa . Javascript Maps mantiene las claves en orden de inserción, lo que significa que puede iterar sobre ellas sin tener que verificar hasOwnProperty, que siempre fue realmente un truco.

Iterar sobre un mapa:

var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (var [key, value] of myMap) {
  console.log(key + " = " + value);
}
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

for (var key of myMap.keys()) {
  console.log(key);
}
// Will show 2 logs; first with "0" and second with "1"

for (var value of myMap.values()) {
  console.log(value);
}
// Will show 2 logs; first with "zero" and second with "one"

for (var [key, value] of myMap.entries()) {
  console.log(key + " = " + value);
}
// Will show 2 logs; first with "0 = zero" and second with "1 = one"

o usar para cada:

myMap.forEach(function(value, key) {
  console.log(key + " = " + value);
}, myMap)
// Will show 2 logs; first with "0 = zero" and second with "1 = one"
Pablo
fuente
1
forEach is the one
preferred
14

Si desea la clave y el valor al iterar, puede usar un bucle for ... of con Object.entries .

const myObj = {a: 1, b: 2}

for (let [key, value] of Object.entries(myObj)) {
    console.log(`key=${key} value=${value}`)
}

// output: 
// key=a value=1
// key=b value=2
Derek Soike
fuente
7

La única forma confiable de hacer esto sería guardar sus datos de objeto en 2 matrices, una de claves y otra para los datos:

var keys = [];
var data = [];
for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        keys.push(key);
        data.push(obj[key]); // Not necessary, but cleaner, in my opinion. See the example below.
    }
}

Luego puede iterar sobre las matrices como lo haría normalmente:

for(var i = 0; i < 100; i++){
    console.log(keys[i], data[i]);
    //or
    console.log(keys[i], obj[keys[i]]); // harder to read, I think.
}
for(var i = 100; i < 300; i++){
    console.log(keys[i], data[i]);
}

No estoy usando Object.keys(obj), porque eso es IE 9+.

Cerbrus
fuente
3

-> si iteramos sobre un objeto JavaScript usando y encontramos la clave de la matriz de objetos

Object.keys(Array).forEach(key => {

 console.log('key',key)

})
ashishdudhat
fuente
1

Si desea iterar todo el objeto a la vez, puede usar el for inbucle:

for (var i in obj) {
  ...
}

Pero si quieres dividir el objeto en partes, de hecho no puedes. No hay garantía de que las propiedades en el objeto estén en un orden específico. Por lo tanto, puedo pensar en dos soluciones.

El primero de ellos es "eliminar" las propiedades ya leídas:

var i = 0;
for (var key in obj) {
    console.log(obj[key]);
    delete obj[key];
    if ( ++i > 300) break;
}

Otra solución que se me ocurre es usar Array of Arrays en lugar del objeto:

var obj = [['key1', 'value1'], ['key2', 'value2']];

Entonces, el forbucle estándar funcionará.

Michał Miszczyszyn
fuente
1

Finalmente se me ocurrió una útil función de utilidad con una interfaz unificada para iterar objetos, cadenas, matrices, matrices escritas, mapas, conjuntos (cualquier Iterables).

const iterate = require('@a-z/iterate-it');
const obj = { a: 1, b: 2, c: 3 };

iterate(obj, (value, key) => console.log(key, value)); 
// a 1
// b 2
// c 3

https://github.com/alrik/iterate-javascript

Alrik Zachert
fuente
1

Puede intentar usar lodash: una moderna biblioteca de utilidad de JavaScript que ofrece modularidad, rendimiento y extras js para iterar objetos rápidamente:

var  users  =   {
    'fred':     { 
        'user':   'fred',
            'age':  40 
    },
    'pebbles':  { 
        'user':   'pebbles',
         'age':  1 
    }
}; 
_.mapValues(users,  function(o)  { 
    return  o.age; 
});
// => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
// The `_.property` iteratee shorthand.
console.log(_.mapValues(users,  'age')); // returns age property & value 
console.log(_.mapValues(users,  'user')); // returns user property & value 
console.log(_.mapValues(users)); // returns all objects 
// => { 'fred': 40, 'pebbles': 1 } (iteration order is not guaranteed)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash-compat/3.10.2/lodash.js"></script>

Parth Raval
fuente
1

Para la iteración de objetos usualmente usamos un for..inbucle. Esta estructura recorrerá todas las propiedades enumerables , incluidas las que se heredan mediante herencia prototípica. Por ejemplo:

let obj = {
  prop1: '1',
  prop2: '2'
}

for(let el in obj) {
  console.log(el);
  console.log(obj[el]);
}

Sin embargo, for..inrecorrerá todos los elementos enumerables y esto no nos permitirá dividir la iteración en fragmentos. Para lograr esto, podemos usar la Object.keys()función integrada para recuperar todas las claves de un objeto en una matriz. Luego podemos dividir la iteración en múltiples bucles for y acceder a las propiedades usando la matriz de claves. Por ejemplo:

let obj = {
  prop1: '1',
  prop2: '2',
  prop3: '3',
  prop4: '4',
};

const keys = Object.keys(obj);
console.log(keys);


for (let i = 0; i < 2; i++) {
  console.log(obj[keys[i]]);
}


for (let i = 2; i < 4; i++) {
  console.log(obj[keys[i]]);
}

Willem van der Veen
fuente
0
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
1
En realidad no. Esto implica que Objects están en orden. Ellos no están. If you can make sense of the sentence it workedsolo funciona debido a los detalles de implementación. No se garantiza que funcione en absoluto. Además, no debe TitleCase sus funciones y variables. Eso es para classes.
Florian Wendelborn
0

Realmente un PITA, esto no es parte del Javascript estándar.

/**
 * Iterates the keys and values of an object.  Object.keys is used to extract the keys.
 * @param object The object to iterate
 * @param fn (value,key)=>{}
 */
function objectForEach(object, fn) {
    Object.keys(object).forEach(key => {
        fn(object[key],key, object)
    })
}

Nota: Cambié los parámetros de devolución de llamada a (valor, clave) y agregué un tercer objeto para que la API sea coherente con otras API.

Úselo así

const o = {a:1, b:true};
objectForEach(o, (value, key, obj)=>{
    // do something
});
Steven Spungin
fuente
1
votó solo por su declaración en la primera oración. Aunque sería mejor si el valor fuera el primer parámetro, el índice o el segundo parámetro clave, y el tercer parámetro del objeto, para que se parezca más a la matriz para cada (). Sin embargo, recomendaría recomendar lodash.
contrato dice que estoy en lo correcto el
Me gusta la idea del orden (valor, clave). Así es como lo hace una biblioteca como Vue. Debido a que el objeto es el contexto, sin embargo, cree que pertenece como primer parámetro. Eso es bastante estándar para la programación funcional.
Steven Spungin
Estoy de acuerdo aquí, si no fuera por ECMA-262 que define una matriz como un objeto que tiene un forEach (), map (), reduce (), filter (), que toman devoluciones de llamada que reciben el pedido [valor, índice, matriz] . Un objeto en JS puede entenderse como simplemente otra colección; y luego estos métodos se unifican en sus parámetros de [valor, clave | índice, contexto] (esto es lo que están haciendo lodash y subrayado). En mi opinión, este protocolo de "colección unificada" es simplemente más fuerte. Además, el objeto no es el contexto: puede establecer thislo que quiera para la devolución de llamada, ya que la devolución de llamada tiene su propio contexto.
contrato dice que estoy
Quizás debería haber usado el receptor de trabajo en lugar de esto. De todos modos sigue siendo un PITA; Agradecería los parámetros en cualquier orden.
Steven Spungin
Oh, veo que podríamos habernos malinterpretado. Siempre comentaba sobre los parámetros de devolución de llamada y su orden, no sobre la objectForEachfunción real . Lo siento si eso fue confuso.
CONTRATO DICE QUE ESTOY CORRECTO
0

Si. Puede recorrer un objeto usando for loop. Aquí hay un ejemplo

var myObj = {
    abc: 'ABC',
    bca: 'BCA',
    zzz: 'ZZZ',
    xxx: 'XXX',
    ccc: 'CCC',
}

var k = Object.keys (myObj);
for (var i = 0; i < k.length; i++) {
    console.log (k[i] + ": " + myObj[k[i]]);
}

NOTA: el ejemplo mencionado anteriormente solo funcionará en IE9 +. Consulte el soporte del navegador Objec.keys aquí .

Omprakash Arumugam
fuente
0
const o = {
  name: "Max",
  location: "London"
};

for (const [key, value] of Object.entries(o)) {
  console.log(`${key}: ${value}`);
}

Probar en línea

Vishal
fuente