Como iterar sobre um objeto JavaScript?

422

Eu tenho um objeto em JavaScript:

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

Eu quero usar um forloop para obter suas propriedades. E quero iterá-lo em partes (nem todas as propriedades do objeto de uma vez).

Com uma matriz simples, posso fazer isso com um forloop padrão :

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

Mas como fazer isso com objetos?

nkuhta
fonte
22
Lembre-se de que as propriedades do objeto não são armazenadas em ordem. Quando você itera sobre um objeto, não há garantia para a ordem em que eles aparecerão.
James Allardice

Respostas:

850

Para a maioria dos objetos, use for .. in:

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

Com o ES6, se você precisar de chaves e valores simultaneamente, faça

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

Para evitar o registro de propriedades herdadas, verifique com hasOwnProperty :

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

Você não precisa verificar hasOwnPropertyao iterar as chaves se estiver usando um objeto simples (por exemplo, um com que você se criou {}).

Esta documentação do MDN explica de maneira mais geral como lidar com objetos e suas propriedades.

Se você quiser fazê-lo "em partes", o melhor é extrair as chaves em uma matriz. Como o pedido não é garantido, esta é a maneira correta. Nos navegadores modernos, você pode usar

let keys = Object.keys(yourobject);

Para ser mais compatível, é melhor fazer o seguinte:

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

Em seguida, você pode iterar suas propriedades 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
fonte
3
O OP deseja executar isso em partes, nem todas as chaves em um único loop.
Pawel
Sim. Objeto não completo em um loop.
Nkashta
2
@ Cerbrus O OP já sabe como iterar uma matriz em partes. Usar keyso código fornecido deve ser suficiente.
Yoshi
2
@ Cerbrus Por favor, leia antes de comentar! O que não está claro em "Para ser mais compatível, é melhor fazer isso" ?
Denys Séguret
2
@ am05mhz Como eu disse, é inútil na maioria dos objetos. Mas não para todos. Tente isso: jsbin.com/hirivubuta/1/edit?js,console,output
Denys Séguret
61

Aqui está outra solução de iteração para navegadores modernos:

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

Ou sem a função de filtro:

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

No entanto, você deve considerar que as propriedades no objeto JavaScript não são classificadas, ou seja, não têm ordem.

Visão
fonte
Se eu quebrar o loop, ele começará do início do objeto na próxima vez, que não é o caminho certo.
Nkashta
21

Usando Object.entriesvocê, faça algo assim.

 // 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'] ]

O método Object.entries () retorna uma matriz da propriedade enumerável de um determinado objeto [chave, valor]

Então você pode iterar sobre o Objeto e ter keye valuepara cada um dos objetos e obter algo parecido com isto.

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

ou assim

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

Para uma referência, consulte os documentos MDN para Entradas de objeto

Adeel Imran
fonte
18

Com os novos recursos do ES6 / ES2015, você não precisa mais usar um objeto para iterar sobre um hash. Você pode usar um mapa . Os mapas Javascript mantêm as chaves em ordem de inserção, o que significa que você pode iterá-las sem precisar verificar o hasOwnProperty, que sempre foi realmente um hack.

Iterar sobre um 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"

ou use forEach:

myMap.forEach(function(value, key) {
  console.log(key + " = " + value);
}, myMap)
// Will show 2 logs; first with "0 = zero" and second with "1 = one"
Paulo
fonte
1
forEach é o preferido
pungggi
14

Se você deseja a chave e o valor ao iterar, pode usar um loop for ... com 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
fonte
7

A única maneira confiável de fazer isso seria salvar os dados do objeto em 2 matrizes, uma das chaves e outra para os dados:

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

Você pode iterar sobre as matrizes como faria 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]);
}

Não estou usando Object.keys(obj), porque é o IE 9+.

Cerbrus
fonte
3

-> se iterarmos sobre um objeto JavaScript usando e encontrarmos a chave da matriz de objetos

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

 console.log('key',key)

})
ashishdudhat
fonte
1

Se você quiser iterar todo o objeto de uma só vez, poderá usar o for inloop:

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

Mas se você deseja dividir o objeto em partes, na verdade não pode. Não há garantia de que as propriedades no objeto estejam em qualquer ordem especificada. Portanto, posso pensar em duas soluções.

O primeiro deles é "remover" as propriedades já lidas:

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

Outra solução em que posso pensar é usar Array of Arrays em vez do objeto:

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

Então, o forloop padrão funcionará.

Michał Miszczyszyn
fonte
1

Finalmente, criei uma função útil de utilitário com uma interface unificada para iterar Objetos, Strings, Arrays, TypedArrays, Maps, Sets, (quaisquer 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
fonte
1

Você pode tentar usar o lodash- Uma moderna biblioteca de utilitários JavaScript que fornece js de modularidade, desempenho e extras para iteração rápida de objetos: -

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
fonte
1

Para iteração de objetos, geralmente usamos um for..inloop. Essa estrutura percorrerá todas as propriedades enumeráveis , incluindo aquelas herdadas por herança prototípica. Por exemplo:

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

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

No entanto, for..infará um loop sobre todos os elementos enumeráveis ​​e isso não nos permitirá dividir a iteração em partes. Para conseguir isso, podemos usar a Object.keys()função incorporada para recuperar todas as chaves de um objeto em uma matriz. Em seguida, podemos dividir a iteração em vários loops e acessar as propriedades usando a matriz de chaves. Por exemplo:

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
fonte
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
fonte
1
Na verdade não. Isso implica que Objects estão em ordem. Eles não são. If you can make sense of the sentence it workedsó funciona devido a detalhes de implementação. Não é garantido que funcione. Além disso, você não deve TitleCase suas funções e variáveis. Isso é para classes.
Florian Wendelborn
0

Realmente uma PITA, isso não faz parte do Javascript padrão.

/**
 * 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: mudei os parâmetros de retorno de chamada para (valor, chave) e adicionei um terceiro objeto para tornar a API consistente com outras APIs.

Use-o assim

const o = {a:1, b:true};
objectForEach(o, (value, key, obj)=>{
    // do something
});
Steven Spungin
fonte
1
votado apenas pela sua afirmação na primeira frase. Mesmo que seja melhor se o valor for o primeiro parâmetro, o segundo índice ou a chave segundo e o terceiro parâmetro do objeto, torná-lo mais parecido com a matriz forEach (). Eu recomendo recomendar lodash embora.
CONTRATO DIZ QUE ESTOU CERTO
Eu gosto da ideia da ordem (valor, chave). É assim que uma biblioteca como a Vue também o faz. Como o objeto é o contexto, ele acha que pertence ao primeiro parâmetro. Isso é bastante padrão para programação funcional.
Steven Spungin
Concordo aqui, não fosse o ECMA-262 que define uma matriz como um objeto com um forEach (), map (), reduzem (), filter (), que todos recebem retornos de chamada recebendo a ordem [valor, índice, matriz] . Um objeto em JS pode ser entendido como apenas outra coleção; e então esses métodos se tornam unificados em seus parâmetros de [valor, chave | índice, contexto] (é isso que lodash e sublinhado estão fazendo). Na minha opinião, esse protocolo de "coleção unificada" é apenas mais forte. Além disso, o objeto não é o contexto: você pode definir thiso que quiser para o retorno de chamada, pois o retorno de chamada possui seu próprio contexto.
CONTRATO DIZ QUE ESTOU CERTO
Talvez eu devesse ter usado o receptor de trabalho em vez disso. De qualquer forma ainda é uma PITA; Gostaria de receber os parâmetros em qualquer ordem.
Steven Spungin
Oh, vejo que podemos nos entender mal. Eu estava sempre comentando sobre os parâmetros de retorno de chamada e sua ordem, não sobre a objectForEachfunção real . Desculpe se isso foi confuso.
CONTRATO DIZ QUE ESTOU CERTO
0

Sim. Você pode percorrer um objeto usando o loop for. Aqui está um exemplo

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: o exemplo mencionado acima funcionará apenas no IE9 +. Consulte o suporte ao navegador Objec.keys aqui .

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

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

Experimente on-line

Vishal
fonte