Como percorrer um objeto JavaScript simples com os objetos como membros?

1601

Como posso percorrer todos os membros em um objeto JavaScript, incluindo valores que são objetos.

Por exemplo, como eu poderia percorrer isso (acessando o "seu_nome" e "sua_mensagem" para cada um)?

var validation_messages = {
    "key_1": {
        "your_name": "jimmy",
        "your_msg": "hello world"
    },
    "key_2": {
        "your_name": "billy",
        "your_msg": "foo equals bar"
    }
}
Edt
fonte
11
possível duplicata de loop através de objetos JavaScript
BUZZ-Dee

Respostas:

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]);
    }
}
AgileJon
fonte
13
O Internet Explorer não concorda ( suspiro ), diz "O objeto não suporta esta propriedade ou método" quando você faz obj [prop]. Ainda não encontrei uma solução para isso.
user999717
2
@MildFuzz, na verdade, faz sentido se você considerar que os objetos JS não precisam ter chaves numéricas. Você não pode simplesmente percorrer um objeto. JS for iné muito semelhante a um tradicional foreach.
27413 Jake Wilson
4
for ... in é uma boa solução, mas se você usar promessas no loop for () - tenha cuidado, porque se você criar um var no loop, não poderá usá-lo na função then da promessa. Você var no loop existe apenas uma vez, portanto, em todas as funções então o mesmo, até o último valor. Se você tiver esse problema, tente "Object.keys (obj) .forEach" ou minha resposta abaixo.
Biber
O hasOwnProperty quase sempre é redundante para navegadores modernos (IE9 +).
Filyus
775

No ECMAScript 5, você pode combinar Object.keys()e 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]);

});

Axel Rauschmayer
fonte
34
+1 por brevidade do código, mas, aparentemente, não é tão eficiente quanto o de surpreendentemente. JSPerf - for in vs Object.keys
techiev2
6
Cuidado com este erro usando esta abordagem: "TypeError: Object.keys chamado non-object". O for ... in ... hasOwnPropertypadrão pode ser chamado em qualquer coisa, até onde eu saiba (objeto, matriz, nulo, indefinido, verdadeiro, falso, número primitivo, objetos).
Theazureshadow
2
Observe que o IE7 não suporta isso.
Paul D. Waite
3
@ techiev2 esses testes nunca foram válidos. Ver meus queridos atualizados para o atual estado de execução: jsperf.com/objdir/20
OrganicPanda
4
@ techiev2: não é o Object.keys()que o torna lento, é sim o forEach()e o acesso repetido a .length! Se você usar um clássico for-loop vez, é quase duas vezes mais rápido for..in+ hasOwnProperty()no Firefox 33.
CodeManX
384

O problema com isso

for (var key in validation_messages) {
   var obj = validation_messages[key];
   for (var prop in obj) {
      alert(prop + " = " + obj[prop]);
   }
}

é que você também percorrerá o protótipo do objeto primitivo.

Com este, você o evitará:

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]);
         }
      }
   }
}
Chango
fonte
46
Em resumo: verifique hasOwnPropertydentro de seus for- inloops.
Rory O'Kane
59
Observe que isso só é necessário se o seu objeto tiver métodos de protótipo. Por exemplo, se o objeto pelo qual você faz o loop for apenas um objeto JSON, você não precisará dessa verificação.
Gitaarik
6
@rednaw Para ser seguro, uso essa verificação porque o Object.prototype pode ser modificado. Nenhum script sensato faria isso, mas você não pode controlar quais scripts podem ser executados na sua página por extensões insanas do navegador. As extensões do navegador são executadas na sua página (na maioria dos navegadores) e podem causar problemas estranhos (por exemplo, defina window.setTimeout como null!).
Robocat
1
Muito obrigado
Blue Tram
328

No ES6 / 2015, você pode percorrer um objeto como este: (usando a função de seta )

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

No ES7 / 2016, você pode usar em Object.entriesvez de Object.keyse fazer um loop através de um 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.
});

O acima também funcionaria como uma linha :

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

jsbin

Caso deseje fazer um loop através de objetos aninhados, você pode usar uma função 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 à função acima, mas com ES7 em Object.entries() vez 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.
  });
};

Aqui, percorreremos objetos aninhados, alterar valores e retornar um novo objeto de uma só vez usando Object.entries()combinado com 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.
    })
  );
Rotareti
fonte
2
Para o seu ES7 usando o exemplo Object.entries, é necessário agrupar os parâmetros da função da seta [key, val] entre parênteses como: `Object.entries (myObj) .forEach (([key, val]) => {/ * declarações * /}
puiu
6
Eu acho que seria útil acrescentar o fato de que Object.entries e Object.keys não iteram sobre o protótipo, que é a grande diferença entre ele e o construto for.
steviejay
Muito obrigado
Blue Tram
95

Usando o Underscore.js_.each :

_.each(validation_messages, function(value, key){
    _.each(value, function(value, key){
        console.log(value);
    });
});
Tim Santeford
fonte
4
Obrigado Tim, usando sublinhado, então é definitivamente bom ter uma opção rápida e limpa.
A Coder
56

Se você usar recursão, poderá retornar propriedades de objetos de qualquer profundidade

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
}

*/
Kennebec
fonte
2
Cuidado com os loops, como chamar isso em um nó DOM.
Theazureshadow 12/10/12
45

Esta resposta é um agregado das soluções que foram fornecidas nesta postagem com alguns feedbacks de desempenho . Acho que existem 2 casos de uso e o OP não mencionou se ele precisa acessar as chaves para usá-las durante o processo de loop.

I. as chaves precisam ser acessadas,

✔ a abordagem ofeObject.keys

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

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

✔ a inabordagem

let k;
for (k in obj) {

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

Use este com cautela, pois pode imprimir propriedades protótipo de obj

✔ a abordagem ES7

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

}

No entanto, no momento da edição, eu não recomendaria o método ES7, porque o JavaScript inicializa muitas variáveis ​​internamente para criar esse procedimento (consulte os feedbacks para obter provas). A menos que você não esteja desenvolvendo um aplicativo enorme que mereça otimização, tudo bem, mas se a otimização for sua prioridade, pense nisso.

II só precisamos acessar cada valor,

✔ a abordagem ofeObject.values

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

}

Mais feedbacks sobre os testes:

  • Armazenamento em cache Object.keysou Object.valuesdesempenho é insignificante

Por exemplo,

const keys = Object.keys(obj);
let i;
for (i of keys) {
  //
}
// same as
for (i of Object.keys(obj)) {
  //
}
  • Por Object.valuesexemplo, o uso de um forloop nativo com variáveis ​​em cache no Firefox parece ser um pouco mais rápido do que o uso de um for...ofloop. No entanto, a diferença não é tão importante e Chrome está sendo executado for...ofmais rápido do que nativa forloop, então eu recomendaria a utilização for...ofquando se lida com Object.valuesem todos os casos (4 e 6 testes).

  • No Firefox, o for...inloop é muito lento; portanto, quando queremos armazenar em cache a chave durante a iteração, é melhor usá-la Object.keys. Além disso, o Chrome está executando a estrutura em velocidade igual (primeiro e último teste).

Você pode verificar os testes aqui: https://jsperf.com/es7-and-misc-loops

vdegenne
fonte
2
O exemplo do ES7 funciona como um encanto com o React Native!
Ty Bailey
Bem explicado. Obrigado
Alok Ranjan
30

Sei que está muito tarde, mas levei dois minutos para escrever esta versão otimizada e aprimorada da resposta do 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]);
            }

        }

    }

}
Azder
fonte
1
Por que você está armazenando hasOwnPropertyem ownse, em seguida, chamando owns.call(obj, prop)ao invés de apenas chamar obj.hasOwnProperty(prop)como esta resposta faz?
Rory O'Kane
14
Como objpode ter a hasOwnPropertyfunção definida por si mesma, não utilizará a de Object.prototype. Você pode tentar antes do forloop assim obj.hasOwnProperty = function(){return false;}e ele não irá iterar sobre nenhuma propriedade.
Azder
4
@ Azz +1 para a resposta e +1 se eu puder pelo melhor de Object.prototype.hasOwnProperty. Vi isso anteriormente dentro do código fonte da biblioteca de sublinhado, mas não sei 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);
}
caos
fonte
14

p é o valor

for (var key in p) {
  alert(key + ' => ' + p[key]);
}

OU

Object.keys(p).forEach(key => { console.log(key, p[key]) })
Wesam
fonte
9

No ES7, você pode fazer:

for (const [key, value] of Object.entries(obj)) {
  //
}
Kévin Berthommier
fonte
Fiz alguns testes, esse método é realmente lento ao lidar com grande quantidade de dados.
precisa saber é o seguinte
8
for(var key in validation_messages){
    for(var subkey in validation_messages[key]){
        //code here
        //subkey being value, key being 'yourname' / 'yourmsg'
    }
}
Dmitri Farkov
fonte
7

Poucas maneiras de fazer isso ...

1) 2 camadas para ... em loop ...

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) função 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]);
    }
  }
}

E chame assim:

recursiveObj(validation_messages);
Alireza
fonte
5

Aí vem a versão aprimorada e recursiva da solução AgileJon ( demo ):

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 solução funciona para todos os tipos de profundidades diferentes.

JepZ
fonte
5

Outra opção:

var testObj = {test: true, test1: false};
for(let x of Object.keys(testObj)){
    console.log(x);
}
cara
fonte
Eu tentei sua solução no Chrome 55.0 e você recebe um erro de tipo. Sua resposta parece agradável e sucinta, se você conseguir fazê-la funcionar, provavelmente seria uma das melhores opções. Tentei descobrir isso, mas não entendo sua solução.
TolMera
2
@TolMera Fixed.
cara
4

O ECMAScript-2017, finalizado há um mês, apresenta Object.values ​​(). Então agora você pode fazer isso:

let v;
for (v of Object.values(validation_messages))
   console.log(v.your_name);   // jimmy billy
Chong Lip Phang
fonte
3

Eu acho que vale ressaltar que o jQuery classifica isso bem com $.each() .

Consulte: https://api.jquery.com/each/

Por exemplo:

$('.foo').each(function() {
    console.log($(this));
});

$(this)sendo o único item dentro do objeto. Troque $('.foo')para uma variável se você não quiser usar o mecanismo de seleção do jQuery.

Daniel Dewhurst
fonte
3

var obj={
name:"SanD",
age:"27"
}
Object.keys(obj).forEach((key)=>console.log(key,obj[key]));

Para percorrer o JavaScript Object, podemos usar o forEach e, para otimizar o código, podemos usar a função de seta

Sandip Bailkar
fonte
2

Não consegui que as postagens acima fizessem exatamente o que eu estava procurando.

Depois de brincar com as outras respostas aqui, eu fiz isso. É hacky, mas 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);
}

... produz isso no console:

myObj.pageURL = BLAH
myObj.emailBox.model = emailAddress
myObj.emailBox.selector = #emailAddress
myObj.passwordBox.model = password
myObj.passwordBox.selector = #password
user1833875
fonte
0

A solução que funciona para mim é a seguinte

_private.convertParams=function(params){
    var params= [];
    Object.keys(values).forEach(function(key) {
        params.push({"id":key,"option":"Igual","value":params[key].id})
    });
    return params;
}
Jorge Santos Neill
fonte
0

Exótico - travessia profunda

JSON.stringify(validation_messages,(field,value)=>{
  if(!field) return value;

  // ... your code

  return value;
})

Nesta solução, usamos o substituto que permite percorrer profundamente todo o objeto e objetos aninhados - em cada nível, você obterá todos os campos e valores. Se você precisar obter o caminho completo para cada campo, procure aqui

Kamil Kiełczewski
fonte
-6

No meu caso (com base no anterior) é possível qualquer número de níveis.

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"]
user2515312
fonte