Iterar pelas propriedades do objeto

2040

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

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

Como a variável proptrepresenta as propriedades do objeto? Não é um método ou propriedade interno. Por que ele cria todas as propriedades do objeto?

Rafay
fonte
11
if (typeof(obj[propt]) === 'object') {/ * Faça isso de novo * /}
noob
13
Bem, sinto muito por esta pergunta. Eu sei o que é um loop, eu não conseguia entender "looping através das propriedades do objeto", o que acho que está limpo agora. Além disso, eles me recomendaram "JavaScript Step by Step 2nd Edition - Steve Suehring na escola.
Rafay
242
Esta é uma boa pergunta para iniciantes. Eu acrescentaria que tenho 15 anos de experiência profissional com outros idiomas e precisava dessa resposta. Eu teria mais de 2000, se pudesse.
13138 Nathan C. Tresch
60
Louco, mas venho a esta página todos os meses há alguns anos para reaprender a sintaxe de como fazer isso. Eu não me incomodo em lembrar como fazer isso ... Apenas lembro que esta página está sempre aqui no SO.
HDave
14
Esta é a página mais estranha que eu já vi no StackOverflow. Se você ler a pergunta com atenção, apenas uma resposta começará a tentar responder ao que realmente está sendo solicitado, e ela terá uma pontuação de -6. A resposta de pontuação mais alta, que foi aceita, não apenas não responde, mas está simplesmente errada.

Respostas:

2426

A iteração sobre propriedades requer esta hasOwnPropertyverificação adicional :

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

É necessário porque o protótipo de um objeto contém propriedades adicionais para o objeto que são tecnicamente parte do objeto. Essas propriedades adicionais são herdadas da classe de objeto base, mas ainda são propriedades de obj.

hasOwnProperty simplesmente verifica se essa é uma propriedade específica dessa classe e não herdada da classe base.


Também é possível chamar hasOwnPropertyatravés do próprio objeto:

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

Mas isso falhará se o objeto tiver um campo não relacionado com o mesmo nome:

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

É por isso que é mais seguro fazê-lo Object.prototype:

var obj = { foo: 42, hasOwnProperty: 'lol' };
Object.prototype.hasOwnProperty.call(obj, 'foo');  // true
Lambda Fairy
fonte
21
@BT De acordo com a documentação da Mozilla : "Se você quiser considerar apenas as propriedades anexadas ao próprio objeto, e não seus protótipos, use getOwnPropertyNames ou execute uma verificação hasOwnProperty (propertyIsEnumerable também pode ser usado)."
Davidmdem 06/08
3
Qual é exatamente o ponto de ligar object.hasOwnProperty()? O fato de propertyter algum valor não implica que está dentro object?
Alex S
6
Porque, Alex S, o protótipo de um objeto contém propriedades adicionais para o objeto que são tecnicamente parte do objeto. Eles são herdados da classe de objeto base, mas ainda são propriedades. O hasOwnProperty simplesmente verifica se essa é uma propriedade específica dessa classe e não herdada da classe base. Uma boa explicação: brianflove.com/2013/09/05/javascripts-hasownproperty-method
Kyle Richter
87
Sinto que devo mencionar, no entanto, que Object.keys (obj) agora é uma solução muito melhor para obter as chaves do próprio objeto. Link para a documentação do Mozilla: developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/… #
Kyle Richter
9
Falta uma informação importante. propertyé uma string aqui, deveria ter sido chamada propertyName. Caso contrário, pode causar confusão para iniciantes em JS como eu, ou seja, o que fazer dentro do if.
Neolisk
1136

No JavaScript 1.8.5, você pode usar Object.keys(obj)para obter uma matriz de propriedades definida no próprio objeto (aquelas que retornam verdadeiras 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 
});

Isso é melhor (e mais legível) do que usar um loop for-in.

É suportado nestes navegadores:

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

Veja o Mozilla Developer Network Object.keys () 's de referência para mais informações.

Danny R
fonte
7
Agora isso é mais amplamente suportado: developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Dom Vinyard
3
E se você precisar de suporte para navegadores antigos, você pode usar este polyfill
KyleMit
27
Em ambientes que suportam essa construção de linguagem, esse método permite que Array.foreach seja chamado: Object.keys(myObject).forEach(function(key,index) { //key = the name of the object key //index = the ordinal position of the key within the object });
Todd Price
4
@ AJ_83 Não há uma boa maneira de sair de um forEach (). Use some () neste caso e retorne true para break
Daniel Z.
11
por que isso é mais legível que o for-in? for candidate in candidateStatus... parece legível para mim
Jona
309

Garotas e garotos que estamos em 2019 e não temos muito tempo para digitar ... Então, vamos fazer este novo ECMAScript 2016 chique e legal:

Object.keys(obj).forEach(e => console.log(`key=${e}  value=${obj[e]}`));
Frank Roth
fonte
17
Como isso é diferente da resposta de Danny R?
krillgar
27
É um oneliner e usa o mapa em vez de forEach. E também o console.log satement talvez seja interessante para algumas pessoas.
Frank Roth
Satly, isso não funciona quando obj=window.performance.memory: - / Onde, como for infaz. isto é,var obj = window.performance.memory; for( key in obj ) console.log( 'key=' + key + ' val=' + obj[key] );
Michaelangel007
2
window.performance.memoryé suportado apenas pelo chrome e Object.keys(obj)retorna uma matriz vazia. Isso não tem nada a ver com .map.
31517 Frank Roth
Caso alguém não queira se disfarçar de reestruturar esse liner para fazer mais de uma coisa de cada vez e, publiquei essa essência. É basicamente como a maioria das implementações de hash, e usa em ( (key) => (value) )vez de { key => value }, mas se você não teve que lidar com isso antes, poderia ajudá-lo a visualizá-lo melhor: gist.github.com/the-nose-knows/9f06e745a56ff20519707433e28a4fa8
kayleeFrye_onDeck
216

É o for...in statement( MDN , especificação ECMAScript ).

Você pode lê-lo como " PARA cada propriedade IN do objobjeto, atribuir a cada estabelecimento até o propt variável por sua vez".

Marc B
fonte
1
Muito obrigado, eu entendo agora. Eu estava batendo a cabeça, folheando livros e o Google.
Rafay
21
Concordo com @RightSaidFred, o inoperador ea fordeclaração não estão envolvidos em tudo, a for-indeclaração representa uma produção de gramática em sua própria: for ( LeftHandSideExpression in Expression ),for ( var VariableDeclarationNoIn in Expression )
CMS
2
Estranha essa resposta tem tantos votos positivos, especialmente porque esses comentários populares parecem contradizê-la.
Doug Molineux
9
Por que isso está marcado como resposta? É possivelmente o menos útil para esta discussão ..
computrius
3
Resposta menos útil? Depende do que você acha que o OP estava perguntando; Quando li a pergunta pela primeira vez, parecia uma confusão perplexa sobre o mecanismo pelo qual uma variável pode ser usada para inspecionar as propriedades de um objeto, e que essa resposta explica de forma eloquente (apesar do equívoco 'for-in'). A pergunta "Por que ele cria todas as propriedades" que eu vejo pode implicar que o OP estava procurando hasOwnProperty, mas não o conhece, mas acho que é mais provável que isso fosse o que o OP queria saber e aceitou incorretamente um correto responda a uma pergunta diferente. :-)
Acidentado
157

Nas implementações atualizadas do ES, você pode usar Object.entries:

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

ou

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

Se você deseja iterar sobre os valores, use Object.values:

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

ou

Object.values(obj).forEach(value => ...)
OneHoopyFrood
fonte
essa seria a melhor solução (object.entries ...), mas não posso usá-la. Quando você quiser fazer isso várias vezes e não puder suportá-lo em sua estrutura, poderá usar o polyfill nesta página: developer.mozilla.org/nl/docs/Web/JavaScript/Reference/…
Mario
A terceira sugestão é ótima se você tiver apenas os valores das propriedades. Impressionante!
precisa
27

Se o seu ambiente suportar o ES2017 , eu recomendaria o Object.entries :

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

Conforme mostrado na documentação do Mozillas Object.entries () :

O método Object.entries () retorna uma matriz dos pares de propriedades [chave, valor] da propriedade enumerável de um determinado objeto, na mesma ordem que a fornecida por um loop for ... in (a diferença é que um loop for enumera propriedades na cadeia de protótipos).

Basicamente, com Object.entries, podemos abrir mão da seguinte etapa extra que é necessária com o loop for ... in mais antigo :

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

O jquery permite que você faça isso agora:

$.each( obj, function( key, value ) {
  alert( key + ": " + value );
});
Rob Sedgwick
fonte
1
$.each({foo:1, length:0, bar:2}, function(k,v){console.log(k,v)})$ .each não é adequado para objetos. Se um objeto tiver uma propriedade length e seu valor for zero, todo o objeto será tratado como se fosse uma matriz vazia.
Bob Stein
Detalhes por que acho que essa é uma abordagem que convida a erros .
Bob Stein
21

A resposta de Dominik é perfeita, eu prefiro fazê-lo dessa maneira, pois é mais fácil ler:

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

    // Do stuff...
}
Cyril N.
fonte
Deve estar Objectem maiúsculas, não?
Jonathan
18

As respostas acima são um pouco irritantes, porque elas não explicam o que você faz dentro do loop for depois de garantir que é um objeto: VOCÊ NÃO A ACEITA DIRETAMENTE! Na verdade, você recebeu apenas a CHAVE que precisa aplicar ao 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;
  }
}

Tudo isso é seguro para ECMA5. Até funciona nas versões lame JS como Rhino;)

dylanh724
fonte
15

Para adicionar o uso de ES2015 de Reflect.ownKeys(obj) e também iterar sobre as propriedades por meio de um iterador.

Por exemplo:

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

pode ser iterado por

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

Se você deseja iterar diretamente sobre os valores das chaves de um objeto, pode definir um iterator , assim como os iteradores padrão do JavaScipts para strings, matrizes, matrizes digitadas, Map e Set.

JS tentará iterar através da propriedade padrão do iterador, que deve ser definida como Symbol.iterator.

Se você deseja iterar sobre todos os objetos, pode adicioná-lo como um protótipo de Object:

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

Isso permitiria que você iterasse sobre os valores de um objeto com um loop for ... of, por exemplo:

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

Cuidado : ao escrever esta resposta (junho de 2018), todos os outros navegadores, exceto o IE, suportam geradores e for...ofiteração viaSymbol.iterator

Dimitar Nikovski
fonte
Embora você não esteja realmente respondendo à pergunta do OP, isso foi muito útil para mim, ainda não sabia sobre o 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
fonte
3
Olá, você pode adicionar mais informações sobre sua resposta, fornecendo apenas código não ajuda.
Nicolas
Oi @ Nicolas Adicionei uma explicação linha por linha ao código. Deixe-me saber se ele ainda não está claro
Fouad Boukredine
Como forEach pula valores vazios , acho que você pode se livrar do if e apenas fazer Object.keys(obj).forEach(e => console.log(`key=${e} value=${obj[e]}`));como a resposta de Frank Roth.
Darkproduct
12

O loop for ... in representa cada propriedade em um objeto porque é como um loop for. Você definiu propt no loop for ... in, fazendo:

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

Um loop for ... in itera pelas propriedades enumeráveis ​​de um objeto. Qualquer variável que você definir ou colocar no loop for ... in será alterada cada vez que for para a próxima propriedade que itera. A variável no loop for ... in itera pelas chaves, mas o valor dela é o valor da chave. Por exemplo:

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

Você pode ver como a variável difere do valor da variável. Em contraste, um loop for ... faz o oposto.

Eu espero que isso ajude.

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

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

// a
// 3
// 2
Philll_t
fonte
1
Conforme mencionado em outros comentários, forEaché mais apropriado aqui, pois mapse destina a retornar uma nova matriz com os resultados da chamada do bloco de código em cada iteração. Mas estamos interessados ​​apenas nos efeitos colaterais de cada iteração, não no valor de retorno; portanto, não precisamos da nova matriz que mapnos fornece.
Danny
11
Object.keys(obj).forEach(key =>
  console.log(`key=${key} value=${obj[key]}`)
);
Estrangeiro companheiro
fonte
10

Você pode usar o Lodash. A documentação

var obj = {a: 1, b: 2, c: 3};
_.keys(obj).forEach(function (key) {
    ...
});
viktarpunko
fonte
10
Por que diabos essa "resposta" tem 10 votos positivos? Falha completamente em responder à pergunta. Estou começando a perder a fé na inteligência do desenvolvedor JS comum.
developerbmw
1
@developerbmw Entendo que usar os recursos do ES6 é o caminho mais certo, mas eu respondi há um ano. Por favor, compartilhe seus pensamentos conosco quando tiver um minuto.
viktarpunko
1
A idéia é se concentrar mais nos métodos nativos, em vez de sugerir que o usuário adicione uma biblioteca de 10000 linhas à sua página. Não me interpretem mal, eu gosto de usar Lodash, mas há um tempo e um lugar para isso e não é isso.
9

Seu forloop está repetindo todas as propriedades do objeto obj. propté definido na primeira linha do seu loop for. É uma string que é o nome de uma propriedade do objobjeto. Na primeira iteração do loop, proptseria "nome".

arb
fonte
9

Objetos em JavaScript são coleções de propriedades e, portanto, podem ser repetidos em um para cada instrução.

Você deve pensar objcomo uma coleção de valores-chave.


fonte
! com a importante diferença de que essas 'listas de propriedades' podem ter nomes como chaves, enquanto matrizes JS normais podem ter apenas números como chaves.
Qqwy
9

Atualmente, você pode converter um objeto JS padrão em um objeto iterável apenas adicionando um método Symbol.iterator. Em seguida, você pode usar um for ofloop e acessar seus valores diretamente ou até mesmo usar um operador de propagação no objeto. Legal. Vamos ver como podemos fazer isso:

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
fonte
1
Maneira interessante de fazer isso. Obrigado pela function*descoberta!
Benj 27/01
5

Se estiver executando o Node , recomendo:

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

Embora a resposta com a melhor classificação esteja correta, aqui está um caso de uso alternativo, ou seja, se você estiver iterando sobre um objeto e quiser criar uma matriz no final. Use em .mapvez 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
fonte
4

Também adicionando a maneira 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
fonte
1
@faiz - veja meus comentários, é uma proteção contra ficar preso em loop infinito quando você caminha através de objetos que possuem referências cíclicas
Ondrej Svejdar
3

O que o loop for..in faz é que ele cria uma nova variável (var someVariable) e, em seguida, armazena cada propriedade do objeto especificado nessa nova variável (someVariable) uma por uma. Portanto, se você usar o bloco {}, poderá iterar. Considere o seguinte exemplo.

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

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

console.log(someVariable); // outputs planet
Raman Sohi
fonte
Voto positivo, dada a sua simplicidade. No meu caso de uso, preciso verificar todos os atributos em um objeto quanto a valores desonestos - NaNs, nulos, indefinidos (eram pontos em um gráfico e esses valores impediam o desenho do gráfico). Para obter o valor em vez do nome, basta fazer o loop obj[someVariable]. Talvez a razão pela qual foi tão prejudicada seja porque não é recursiva. Portanto, isso não seria uma solução adequada se você tiver um objeto altamente estruturado.
Katharine Osborne
@KatharineOsborne ou talvez seja porque a frase a seguir é um pouco enigmática: "Portanto, se você usar o bloco {}, poderá iterar." O código diz mais que o texto.
Bdbb
3

Aqui, eu estou iterando cada nó e criando nomes significativos de nós. Se você notar, instanceOf Array e instanceOf Object praticamente fazem a mesma coisa (no meu aplicativo, estou fornecendo uma 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 - Estou inspirado na resposta de Ondrej Svejdar. Mas esta solução tem melhor desempenho e menos ambígua

Faiz Mohamed Haneef
fonte
3

Você basicamente deseja percorrer cada propriedade no 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
fonte
obj(prop)<- TypeError: obj não é uma função
le_m 23/06
@le_m meu mal. Devo acidentalmente remover o hasOwnPropertyatributo. Deve funcionar agora.
HovyTech
2

Quero adicionar as respostas acima, porque você pode ter intenções diferentes do Javascript. Um objeto JSON e um objeto Javascript são coisas diferentes, e você pode querer percorrer as propriedades de um objeto JSON usando as soluções propostas acima e, em seguida, surpreender-se.

Suponha que você tenha um objeto JSON como:

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

A maneira errada de iterar através de suas 'propriedades':

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

Você pode ser surpreendido de ver o registro do console 0, 1etc., quando a iteração através das propriedades prop1e prop2eprop3_1 . Esses objetos são sequências e os índices de uma sequência são propriedades desse objeto em Javascript.

Uma maneira melhor de iterar recursivamente através das propriedades de um objeto JSON seria primeiro verificar se esse objeto é uma sequência ou não:

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

Para refinar ainda mais a resposta aceita, vale a pena notar que, se você instanciar o objeto com um var object = Object.create(null), object.hasOwnProperty(property)acionará um TypeError. Portanto, para estar do lado seguro, você precisa chamá-lo do protótipo assim:

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