Como percorrer ou enumerar um objeto JavaScript?

2880

Eu tenho um objeto JavaScript como o seguinte:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Agora eu quero percorrer todos pos elementos ( p1, p2, p3...) e obter as suas chaves e valores. Como eu posso fazer isso?

Eu posso modificar o objeto JavaScript, se necessário. Meu objetivo final é percorrer alguns pares de valores-chave e, se possível, quero evitar o uso eval.

Tanmoy
fonte
9
Mudei JSON para JavaScript (objeto) para evitar confusão de literais de objeto e JSON.
Felix Kling

Respostas:

4367

Você pode usar o for-inloop como mostrado por outras pessoas. No entanto, você também precisa se certificar de que a chave que obtém é uma propriedade real de um objeto e não vem do protótipo.

Aqui está o trecho:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " -> " + p[key]);
    }
}

For-of com Object.keys () alternativa:

var p = {
    0: "value1",
    "b": "value2",
    key: "value3"
};

for (var key of Object.keys(p)) {
    console.log(key + " -> " + p[key])
}

Observe que o uso de, em for-ofvez de for-in, se não for usado, retornará indefinido nas propriedades nomeadas e Object.keys()assegura o uso apenas das próprias propriedades do objeto sem as propriedades da cadeia de protótipos inteiras

Usando o novo Object.entries()método:

Nota: Este método não é suportado nativamente pelo Internet Explorer. Você pode considerar usar um Polyfill para navegadores mais antigos.

const p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (let [key, value] of Object.entries(p)) {
  console.log(`${key}: ${value}`);
}
levik
fonte
34
Gostaria de propor que você alterar a linha de alerta apenas para maior clareza aalert(key + " -> " + JSON.stringify(p[key]));
Steve Midgley
80
Você pode explicar a necessidade de hasOwnProperty? O que você quer dizer com protótipo?
Kamaci
331
Em javascript, todo objeto possui vários pares de valores-chave incorporados que possuem meta-informações. Quando você percorre todos os pares de valores-chave de um objeto, você também os percorre. hasOwnPropery () os filtra.
Danieltalsky
57
Na verdade, For ... in não é preterido. Para cada ... em é. Mas eu realmente gosto do termo arqueólogos ... vou ter que começar a usar isso.
Ben Y
17
cada objeto em javascript (na verdade, um par de valor-chave) tem uma propriedade chamada __proto__or prototype. Esta propriedade tem uma referência ao seu objeto pai. Um objeto herda automaticamente a propriedade de seu pai. Essa é a razão do uso hasOwnProperty, o que significa que estamos interessados ​​na propriedade dos objetos e não nos seus pais.
Zubair Alam
1104

No ECMAScript 5, você pode combinar Object.keys()e Array.prototype.forEach():

var obj = { first: "John", last: "Doe" };

Object.keys(obj).forEach(function(key) {
    console.log(key, obj[key]);
});

O ECMAScript 6 acrescenta for...of:

for (const key of Object.keys(obj)) {
    console.log(key, obj[key]);
}

O ECMAScript 8 adiciona o Object.entries()que evita a necessidade de procurar cada valor no objeto original:

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

Você pode combinar for...of, desestruturar e Object.entries:

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

As propriedades Object.keys()e Object.entries()iteram na mesma ordem que um for...inloop, mas ignoram a cadeia de protótipos . Somente as propriedades enumeráveis ​​do próprio objeto são iteradas.

Axel Rauschmayer
fonte
21
Por que o padrão não forneceu Object.forEach(obj, function (value, key) {...})? :( Certamente obj.forEach(function...)seria mais curto e complemento Array.prototype.forEach, mas que correria o risco de ter objetos definir a sua própria forEachpropriedade suponho. Object.keysProtege contra o callback modificar chaves do objeto.
David Harkness
7
Object.forEach = function (obj, callback) { Object.keys(obj).forEach(function (key) { callback(obj[key], key); }); }
David Harkness
7
@DavidHarkness Há Object.entries no ES2017. Lá você pode fazer o seguinte: Object.entries(obj).map/forEach(([key, value]) => console.log(key, value))([chave, valor] é variedade desestruturação, para acessar ambos os itens diretamente E você tem que envolver os parâmetros em parênteses adicionais..)
Andreas Linnert
como faço para obter indexa chave em json? Ou, se necessário, devo usar um contador separado?
Saravanabalagi Ramachandran
3
for...ofé o padrão ES6, não o ES2016.
Rax Weber #
342

Você precisa usar o loop for-in

Mas tenha muito cuidado ao usar esse tipo de loop, porque isso fará um loop em todas as propriedades ao longo da cadeia de protótipos .

Portanto, ao usar loops de entrada, sempre use o hasOwnPropertymétodo para determinar se a propriedade atual na iteração é realmente uma propriedade do objeto que você está verificando:

for (var prop in p) {
    if (!p.hasOwnProperty(prop)) {
        //The current property is not a direct property of p
        continue;
    }
    //Do your logic with the property here
}
Andreas Grech
fonte
31
Isso é melhor que a solução da levik, porque permite que a lógica principal seja apenas um loop aninhado em vez de dois; facilitando a leitura de código. Embora eu soltasse os suportes ao redor da continuação; eles são supérfluos.
SystemicPlural
52
Eu não removeria o { }pessoalmente porque um ifsem eles torna um pouco claro o que faz parte ife o que não é. Mas eu acho que é apenas uma questão de opinião :)
pimvdb
34
Sim, prefiro manter o { }principal para evitar confusão, se mais tarde precisar adicionar algo ao ifescopo.
Andreas Grech
8
Lendo meu comentário anterior, percebi que não usava os termos corretos, porque disse "se escopo"; mas lembre-se de que o JavaScript só tem escopo de função. Então, o que eu realmente quis dizer foi "se bloquear".
Andreas Grech 11/11
1
eomeroff, se você está realmente preocupado com isso, você sempre pode fazer algo como: Object.prototype.hasOwnProperty.call(p, prop) No entanto, isso também não pode proteger contra manipulações para Object.prototype ...
jordancpaul
252

A pergunta não estará completa se não mencionarmos métodos alternativos para percorrer objetos.

Atualmente, muitas bibliotecas JavaScript conhecidas fornecem seus próprios métodos para iterar sobre coleções, ou seja, sobre matrizes , objetos e objetos semelhantes a matrizes . Esses métodos são fáceis de usar e são totalmente compatíveis com qualquer navegador.

  1. Se você trabalha com jQuery , pode usar o jQuery.each()método Ele pode ser usado para iterar perfeitamente objetos e matrizes:

    $.each(obj, function(key, value) {
        console.log(key, value);
    });
  2. No Underscore.js, você encontra o método _.each(), que itera sobre uma lista de elementos, resultando cada um em uma função fornecida (preste atenção à ordem dos argumentos na função iteratee !):

    _.each(obj, function(value, key) {
        console.log(key, value);
    });
  3. O Lo-Dash fornece vários métodos para iterar sobre as propriedades do objeto. Básico _.forEach()(ou seu alias _.each()) é útil para fazer loop entre objetos e matrizes, no entanto (!) Objetos com lengthpropriedade são tratados como matrizes, e para evitar esse comportamento, é recomendável usar métodos _.forIn()e _.forOwn()métodos (estes também têm valueargumentos em primeiro lugar):

    _.forIn(obj, function(value, key) {
        console.log(key, value);
    });

    _.forIn()itera sobre propriedades enumeráveis próprias e herdadas de um objeto, enquanto _.forOwn()itera apenas sobre propriedades próprias de um objeto (basicamente verificando a hasOwnPropertyfunção). Para objetos simples e literais de objeto, qualquer um desses métodos funcionará bem.

Geralmente todos os métodos descritos têm o mesmo comportamento com todos os objetos fornecidos. Além de usar o for..inloop nativo , geralmente será mais rápido do que qualquer abstração, como, por exemplo jQuery.each(), esses métodos são consideravelmente mais fáceis de usar, exigem menos codificação e fornecem melhor tratamento de erros.

Visão
fonte
4
Para chegar ao valor: $ .each (obj, função (chave, valor) {console.log (value.title);});
Ravi Ram
2
Apenas engraçado como sublinhado e parâmetros jQuery mudou :)
ppasler
52

No ECMAScript 5, você tem uma nova abordagem nos campos de iteração literal - Object.keys

Mais informações que você pode ver no MDN

Minha opção está abaixo como uma solução mais rápida nas versões atuais de navegadores (Chrome30, IE10, FF25)

var keys = Object.keys(p),
    len = keys.length,
    i = 0,
    prop,
    value;
while (i < len) {
    prop = keys[i];
    value = p[prop];
    i += 1;
}

Você pode comparar o desempenho dessa abordagem com diferentes implementações em jsperf.com :

Suporte ao navegador que você pode ver na tabela de compatibilidade do Kangax

Para o navegador antigo, você tem o polyfill simples e completo

UPD:

comparação de desempenho para todos os casos mais populares nesta pergunta em perfjs.info:

iteração literal do objeto

Pencroff
fonte
Na verdade, eu só queria postar esse método. Mas você me venceu :(
Jamie Hutber
50

Prefácio:

  • As propriedades do objeto podem ser próprias (a propriedade está no próprio objeto) ou herdadas (não no próprio objeto, em um de seus protótipos).
  • As propriedades do objeto podem ser enumeráveis ou não enumeráveis . Propriedades não enumeráveis ​​são deixadas de fora de muitas enumerações / matrizes de propriedades.
  • Os nomes das propriedades podem ser cadeias ou símbolos. As propriedades cujos nomes são Símbolos são deixadas de fora de muitas enumerações / matrizes de propriedades.

Aqui em 2018, suas opções para percorrer as propriedades de um objeto são (alguns exemplos seguem a lista):

  1. for-in[ MDN , spec ] - Uma estrutura de loop que percorre os nomes das propriedades enumeráveis de um objeto , incluindo as herdadas, cujos nomes são cadeias
  2. Object.keys[ MDN , especificação ] - A função de fornecer uma matriz dos nomes dos de um objeto próprio , enumeráveis propriedades cujos nomes são strings.
  3. Object.values[ MDN , especificação ] - Uma função de proporcionar uma matriz de valores de de um objecto próprios , enumeráveis propriedades.
  4. Object.entries[ MDN , especificação ] - Uma função que fornece uma disposição dos nomes e os valores de de um objecto próprios , enumeráveis propriedades (cada entrada na matriz é uma [name, value]matriz).
  5. Object.getOwnPropertyNames[ MDN , especificação ] - A função de fornecer uma matriz dos nomes dos de um objeto próprias propriedades (mesmo os não-enumeráveis) cujos nomes são strings.
  6. Object.getOwnPropertySymbols[ MDN , especificação ] - A função de fornecer uma matriz dos nomes dos de um objeto próprias propriedades (mesmo os não-enumeráveis) cujos nomes são símbolos.
  7. Reflect.ownKeys[ MDN , especificação ] - Uma função que fornece uma disposição dos nomes dos de um objecto próprias propriedades (mesmo aqueles não-enumeráveis), se esses nomes são cadeias de caracteres ou símbolos.
  8. Se você quer tudo de propriedades de um objeto, incluindo aqueles herdados não-enumeráveis, você precisa usar um loop e Object.getPrototypeOf[ MDN , especificação ] e utilização Object.getOwnPropertyNames, Object.getOwnPropertySymbolsou Reflect.ownKeysem cada objeto na cadeia de protótipos (exemplo na parte inferior desta resposta).

Com todos eles, exceto for-in, você pode usar algum tipo de looping construção no array ( for, for-of, forEach, etc.).

Exemplos:

for-in:

Object.keys (com um for-ofloop, mas você pode usar qualquer construção de loop) :

Object.values:

Object.entries:

Object.getOwnPropertyNames:

Object.getOwnPropertySymbols:

Reflect.ownKeys:

Todas as propriedades , incluindo as não enumeráveis ​​herdadas:

TJ Crowder
fonte
Adição agradável de propriedades de objetos enumeráveis ​​/ não enumeráveis.
serraosays
49

Você pode simplesmente iterar sobre isso como:

for (var key in p) {
  alert(p[key]);
}

Observe que keynão assumirá o valor da propriedade, é apenas um valor de índice.

Bryan
fonte
13
Isso é repetido e nem totalmente correto. Você precisa ter uma verificação de hasOwnProperty para fazer este trabalho corretamente
Vatsal
4
Inicialmente, diminuí a votação com base no comentário acima até perceber que essa resposta veio primeiro, portanto, não é "repetida". É possivelmente incompleto, mas funciona muito bem para muitos casos.
billynoah
27

Como o es2015 está se tornando cada vez mais popular, estou postando esta resposta, que inclui o uso de gerador e iterador para iterar suavemente através de [key, value]pares. Como é possível em outros idiomas, por exemplo, Ruby.

Ok, aqui está um código:

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
  [Symbol.iterator]: function* () {
    for (const i of Object.keys(this)) {
      yield [i, this[i]];
    }
  }
};

for (const [k, v] of MyObject) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

Todas as informações sobre como você pode criar um iterador e gerador podem ser encontradas na página do desenvolvedor Mozilla.

Espero que tenha ajudado alguém.

EDITAR:

O ES2017 incluirá o Object.entriesque tornará a iteração sobre [key, value]pares em objetos ainda mais fácil. Sabe-se agora que fará parte de um padrão de acordo com as informações do estágio ts39 .

Acho que está na hora de atualizar minha resposta para deixá-la ainda mais atual do que é agora.

const MyObject = {
  'a': 'Hello',
  'b': 'it\'s',
  'c': 'me',
  'd': 'you',
  'e': 'looking',
  'f': 'for',
};

for (const [k, v] of Object.entries(MyObject)) {
  console.log(`Here is key ${k} and here is value ${v}`);
}

Você pode encontrar mais informações sobre o uso na página MDN

FieryCod
fonte
Isso parece totalmente supérfluo / desnecessário para mim. Você o adicionaria a todos os objetos em seu sistema? Eu pensei que o objetivo de fornecer um iterador era para que você pudesse fazer `por (const [k, v] do myObject) '. Parece código extra, fornecendo pouco valor adicional.
Dean Radcliffe
22
for(key in p) {
  alert( p[key] );
}

Nota: você pode fazer isso através de matrizes, mas também repetirá as lengthpropriedades e outras.

Richard Levasseur
fonte
4
Ao usar um loop for como esse, keyapenas assumirá um valor de índice, de modo que apenas alertará 0, 1, 2, etc ... Você precisa acessar p [tecla].
Bryan
1
É o método mais lento de iteração de matriz em JavaScript. Você pode verificar isso no seu computador - Melhor maneira de iterar sobre matrizes em JavaScript
Pencroff
5
@Pencroff: o problema é que a questão não é sobre um loop através de matrizes ...;)
Sk8erPeter
Isso é algo que eu não entendo no stackoverflow. Richard deu a resposta correta, e ele foi o primeiro a dar essa resposta, mas ele não recebeu +1? @Bryan var p = {"p1":"q","p2":"w"}; for(key in p) { alert( key ); }está aparecendo "p1" e "p2" em alertas, então o que há de errado nisso ???
Sebastian
5
Eu acho que a principal diferença é a qualidade: as outras respostas não apenas dizem como, mas também as advertências (por exemplo, o protótipo) e como lidar com essas advertências. IMHO, essas outras respostas são melhores que as minhas :).
Richard Levasseur
20

Depois de examinar todas as respostas aqui, o hasOwnProperty não é necessário para meu próprio uso porque meu objeto json está limpo; realmente não faz sentido adicionar nenhum processamento javascript adicional. Isso é tudo o que estou usando:

for (var key in p) {
    console.log(key + ' => ' + p[key]);
    // key is key
    // value is p[key]
}
Francis Lewis
fonte
18
Se o objeto JSON está limpo ou não é irrelevante. Se a qualquer momento algum código definir uma propriedadeObject.prototype , ele será enumerado por for..in. Se você tiver certeza de que não está usando nenhuma biblioteca que faça isso, não precisará ligar hasOwnProperty.
G-Wiz
4
Ele pode ser completamente limpo se criado comObject.create(null)
Juan Mendes
20

através da protótipo com forEach (), que deve pular as propriedades da cadeia de protótipos :

Object.prototype.each = function(f) {
    var obj = this
    Object.keys(obj).forEach( function(key) { 
        f( key , obj[key] ) 
    });
}


//print all keys and values
var obj = {a:1,b:2,c:3}
obj.each(function(key,value) { console.log(key + " " + value) });
// a 1
// b 2
// c 3
andarilho
fonte
2
Cuidado com o protótipo: obj = { print: 1, each: 2, word: 3 }produz TypeError: number is not a function. Usar forEachpara combinar com a Arrayfunção semelhante pode reduzir um pouco o risco.
David Harkness
18

É pessoas interessantes nestas respostas tocaram em ambos Object.keys()e for...ofmas nunca combinou-os:

var map = {well:'hello', there:'!'};
for (let key of Object.keys(map))
    console.log(key + ':' + map[key]);

Você pode não apenas for...ofum Object, porque não é um iterador, e for...indexou .forEach()ing o Object.keys()é feio / ineficiente.
Fico feliz que a maioria das pessoas se abstenha de for...in(com ou sem verificação .hasOwnProperty()), pois isso também é um pouco confuso, então, além da minha resposta acima, estou aqui para dizer ...


Você pode fazer associações de objetos comuns iterarem! Comportando-se como Maps com o uso direto da for...of
DEMO chique trabalhando no Chrome e no FF (presumo apenas o ES6)

var ordinaryObject = {well:'hello', there:'!'};
for (let pair of ordinaryObject)
    //key:value
    console.log(pair[0] + ':' + pair[1]);

//or
for (let [key, value] of ordinaryObject)
    console.log(key + ':' + value);

Contanto que você inclua meu calço abaixo:

//makes all objects iterable just like Maps!!! YAY
//iterates over Object.keys() (which already ignores prototype chain for us)
Object.prototype[Symbol.iterator] = function() {
    var keys = Object.keys(this)[Symbol.iterator]();
    var obj = this;
    var output;
    return {next:function() {
        if (!(output = keys.next()).done)
            output.value = [output.value, obj[output.value]];
        return output;
    }};
};

Sem ter que criar um objeto de mapa real que não tenha o bom açúcar sintático.

var trueMap = new Map([['well', 'hello'], ['there', '!']]);
for (let pair of trueMap)
    console.log(pair[0] + ':' + pair[1]);

De fato, com esse calço, se você ainda deseja tirar proveito das outras funcionalidades do Map (sem compor todas), mas ainda deseja usar a notação de objeto, uma vez que os objetos agora são iteráveis, agora você pode fazer um mapa a partir dele!

//shown in demo
var realMap = new Map({well:'hello', there:'!'});

Para quem não gosta de brincar ou mexer prototypeem geral, sinta-se à vontade para fazer a função na janela, chamando-a de algo parecido com getObjIterator()isso;

//no prototype manipulation
function getObjIterator(obj) {
    //create a dummy object instead of adding functionality to all objects
    var iterator = new Object();

    //give it what the shim does but as its own local property
    iterator[Symbol.iterator] = function() {
        var keys = Object.keys(obj)[Symbol.iterator]();
        var output;

        return {next:function() {
            if (!(output = keys.next()).done)
                output.value = [output.value, obj[output.value]];
            return output;
        }};
    };

    return iterator;
}

Agora você pode chamá-lo como uma função comum, nada mais é afetado

var realMap = new Map(getObjIterator({well:'hello', there:'!'}))

ou

for (let pair of getObjIterator(ordinaryObject))

Não há razão para que isso não funcione.

Bem vindo ao futuro.

Hashbrown
fonte
1
Caso em questão . Enquanto as pessoas rolam para baixo e acham útil, isso é tudo o que importa. Geralmente sou eu tentando fazer alguma coisa, não gostando das coisas que vejo online, acabo descobrindo e depois volto a compartilhar. É bom, já encontrei minhas próprias respostas antes de pesquisar sobre coisas que esqueci completamente!
Hashbrown
@HelpMeStackOverflowMyOnlyHope Pessoalmente, não gosto de modificar os protótipos de objetos que não me defini.
Janus Troelsen
@JanusTroelsen você leu a resposta toda? For those who don't like to shim, or mess with prototype in general, feel free to make the function on window instead, calling it something like getObjIterator() then;
Hashbrown 30/09/16
Observe que essa técnica não funciona em objetos simples, mas é útil mesmo assim.
noɥʇʎԀʎzɐɹƆ
funciona para objetos simples, esse é literalmente o ponto principal (assim como os nomes das variáveis, como ordinaryObjectpara enfatizar que a magia ainda funciona para esses tipos). Você checou as demos; o que não está funcionando para você, @ noɥʇʎԀʎzɐɹƆ? (PS sua imagem de perfil SE é chefe)
Hashbrown
13

Object.keys (obj): matriz

recupera todas as chaves com valor de seqüência de caracteres de todas as propriedades enumeráveis ​​próprias (não herdadas).

Portanto, ele fornece a mesma lista de chaves que você pretende, testando cada chave de objeto com hasOwnProperty. Você não precisa dessa operação de teste extra e Object.keys( obj ).forEach(function( key ){})deve ser mais rápida. Vamos provar:

var uniqid = function(){
			var text = "",
					i = 0,
					possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
			for( ; i < 32; i++ ) {
					text += possible.charAt( Math.floor( Math.random() * possible.length ) );
			}
			return text;
		}, 
		CYCLES = 100000,
		obj = {}, 
		p1,
		p2,
		p3,
		key;

// Populate object with random properties
Array.apply( null, Array( CYCLES ) ).forEach(function(){
	obj[ uniqid() ] = new Date()
});

// Approach #1
p1 = performance.now();
Object.keys( obj ).forEach(function( key ){
	var waste = obj[ key ];
});

p2 = performance.now();
console.log( "Object.keys approach took " + (p2 - p1) + " milliseconds.");

// Approach #2
for( key in obj ) {
	if ( obj.hasOwnProperty( key ) ) {
		var waste = obj[ key ];
	}
}

p3 = performance.now();
console.log( "for...in/hasOwnProperty approach took " + (p3 - p2) + " milliseconds.");

No meu Firefox, tenho os seguintes resultados

  • A abordagem Object.keys levou 40,21101451665163 milissegundos.
  • para ... em / a abordagem hasOwnProperty levou 98,26163508463651 milissegundos.

PS. no Chrome, a diferença ainda maior http://codepen.io/dsheiko/pen/JdrqXa

PS2: no ES6 (EcmaScript 2015), você pode iterar objetos iteráveis ​​melhor:

let map = new Map().set('a', 1).set('b', 2);
for (let pair of map) {
    console.log(pair);
}

// OR 
let map = new Map([
    [false, 'no'],
    [true,  'yes'],
]);
map.forEach((value, key) => {
    console.log(key, value);
});

Dmitry Sheiko
fonte
se você não se sentir como deixar de ir a notação {}, você ainda pode usar of sem criar Maps
Hashbrown
13

Aqui está outro método para iterar através de um objeto.

   var p = {
"p1": "value1",
"p2": "value2",
"p3": "value3"
};


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

Harsh Patel
fonte
3
Isso é muito legal, no entanto, para objetos grandes, o formétodo pode ser mais eficiente.
Rolf
13

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

for (var key in p) {
    if (p.hasOwnProperty(key)) {
        console.log(key + " = " + p[key]);
    }
}
<p>
  Output:<br>
  p1 = values1<br>
  p2 = values2<br>
  p3 = values3
</p>

ParaMeterz
fonte
12

Você também pode usar Object.keys () e iterar sobre as chaves de objeto, como abaixo, para obter o valor:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Object.keys(p).forEach((key)=> {
 console.log(key +' -> '+ p[key]);
});

Onera
fonte
Você economizou meu tempo, obrigado
Swap-IOS-Android
Feliz em saber :)
Onera
8

Somente código JavaScript sem dependências:

var p = {"p1": "value1", "p2": "value2", "p3": "value3"};
keys = Object.keys(p);   // ["p1", "p2", "p3"]

for(i = 0; i < keys.length; i++){
  console.log(keys[i] + "=" + p[keys[i]]);   // p1=value1, p2=value2, p3=value3
}
mohamed-ibrahim
fonte
8

O Object.keys()método retorna uma matriz das propriedades enumeráveis ​​de um determinado objeto. Leia mais sobre isso aqui

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3"
};

Object.keys(p).map((key)=> console.log(key + "->" + p[key]))

George Bailey
fonte
8

atuação

Hoje 2020.03.06 realizo testes de soluções escolhidas no Chrome v80.0, Safari v13.0.5 e Firefox 73.0.1 no MacOs High Sierra v10.13.6

Conclusões

  • As soluções baseadas em for-in(A, B) são rápidas (ou mais rápidas) para todos os navegadores para objetos grandes e pequenos
  • surpreendentemente for-of(H) a solução é rápida no chrome para objetos pequenos e grandes
  • soluções baseadas em índice explícito i (J, K) são bastante rápidas em todos os navegadores para objetos pequenos (para o firefox também são rápidas em objetos grandes, mas são rápidas em outros navegadores)
  • soluções baseadas em iteradores (D, E) são mais lentas e não são recomendadas
  • solução C é lenta para objetos grandes e média lenta para objetos pequenos

insira a descrição da imagem aqui

Detalhes

Testes de desempenho foram realizados para

  • objeto pequeno - com 3 campos - você pode executar o teste em sua máquina AQUI
  • objeto 'grande' - com 1000 campos - você pode executar o teste em sua máquina AQUI

Os trechos abaixo apresentam soluções usadas

E aqui estão os resultados para pequenos objetos no chrome

insira a descrição da imagem aqui

Kamil Kiełczewski
fonte
7

Você pode adicionar uma função forEach simples a todos os objetos, para poder percorrer automaticamente qualquer objeto:

Object.defineProperty(Object.prototype, 'forEach', {
    value: function (func) {
        for (var key in this) {
            if (!this.hasOwnProperty(key)) {
                // skip loop if the property is from prototype
                continue;
            }
            var value = this[key];
            func(key, value);
        }
    },
    enumerable: false
});

Para aquelas pessoas que não gostam do método " for ... in ":

Object.defineProperty(Object.prototype, 'forEach', {
    value: function (func) {
        var arr = Object.keys(this);
        for (var i = 0; i < arr.length; i++) {
            var key = arr[i];
            func(key, this[key]);
        }
    },
    enumerable: false
});

Agora, você pode simplesmente ligar para:

p.forEach (function(key, value){
    console.log ("Key: " + key);
    console.log ("Value: " + value);
});

Se você não deseja entrar em conflito com outros métodos forEach, você pode nomear com seu nome exclusivo.

Biber
fonte
3
Modificar os protótipos de objetos Objectinternos (como ) geralmente é considerado um antipadrão, pois pode facilmente causar conflitos com outro código. Portanto, não recomendo fazer dessa maneira.
Moritz
6

Os loops podem ser bastante interessantes ao usar JavaScript puro. Parece que apenas o ECMA6 (nova especificação JavaScript de 2015) controlou os loops. Infelizmente, enquanto escrevo isso, os navegadores e o popular ambiente de desenvolvimento integrado (IDE) ainda estão lutando para oferecer suporte completo aos novos sinos e assobios.

À primeira vista, aqui está a aparência de um loop de objeto JavaScript antes do ECMA6:

for (var key in object) {
  if (p.hasOwnProperty(key)) {
    var value = object[key];
    console.log(key); // This is the key;
    console.log(value); // This is the value;
  }
}

Além disso, eu sei que isso está fora de escopo com esta pergunta, mas em 2011, o ECMAScript 5.1 adicionou o forEachmétodo para Arrays, o que basicamente criou uma nova maneira aprimorada de fazer um loop através de matrizes enquanto ainda deixa objetos não iteráveis ​​com o antigo forloop detalhado e confuso . Mas a parte estranha é que esse novo forEachmétodo não suporta o breakque levou a todos os tipos de outros problemas.

Basicamente, em 2011, não existe uma maneira realmente sólida de fazer loop no JavaScript, além do que muitas bibliotecas populares (jQuery, Underscore etc.) decidiram reimplementar.

A partir de 2015, agora temos uma maneira melhor e imediata de fazer loop (e quebrar) qualquer tipo de objeto (incluindo matrizes e seqüências de caracteres). Aqui está como será um loop em JavaScript quando a recomendação se tornar mainstream:

for (let [key, value] of Object.entries(object)) {
    console.log(key); // This is the key;
    console.log(value); // This is the value;
}

Observe que a maioria dos navegadores não suporta o código acima a partir de 18 de junho de 2016. Mesmo no Chrome, você precisa habilitar este sinalizador especial para que ele funcione: chrome://flags/#enable-javascript-harmony

Até que este se torne o novo padrão, o método antigo ainda pode ser usado, mas também existem alternativas em bibliotecas populares ou até alternativas leves para aqueles que não estão usando nenhuma dessas bibliotecas.

Nicolas Bouvrette
fonte
Você poderia fornecer um violino desse trabalho? Aqui está a minha tentativa. jsfiddle.net/abalter/sceeb211
abalter
@abalter Desculpe, percebi que tinha um erro de digitação no meu código. Eu o corrigi e atualizei o seu JsFiddle aqui: jsfiddle.net/sceeb211/2 #
Nicolas Bouvrette 18/06/16
Estou em cromo e ficando Uncaught TypeError: Object.entries is not a function. Ainda não está implementado no chrome?
abalter
@abalter É. Verifique se você possui a versão 51 do Chrome e se ativou a sinalização, conforme explicado em meus comentários de edição e Jsfiddle. Você pode verificar os detalhes aqui: developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
Nicolas Bouvrette 18/16
Desculpe, eu perdi isso na bandeira. Vejo que ainda não é um recurso totalmente implementado.
abalter
5

No ES6, temos símbolos conhecidos para expor alguns métodos internos anteriormente. Você pode usá-lo para definir como os iteradores funcionam para este objeto:

var p = {
    "p1": "value1",
    "p2": "value2",
    "p3": "value3",
    *[Symbol.iterator]() {
        yield *Object.keys(this);
    }
};

[...p] //["p1", "p2", "p3"]

isso dará o mesmo resultado que usar for ... no loop es6.

for(var key in p) {
    console.log(key);
}

Mas é importante conhecer os recursos que você tem agora usando o es6!

Bamieh
fonte
1
Um iterador de objeto personalizado chama o iterador de matriz interno de uma matriz que é gerada Object.keys()e alocada na memória ... Legal!
ooo
5

Eu faria isso ao invés de verificar obj.hasOwnerPropertydentro de cada for ... inloop.

var obj = {a : 1};
for(var key in obj){
    //obj.hasOwnProperty(key) is not needed.
    console.log(key);
}
//then check if anybody has messed the native object. Put this code at the end of the page.
for(var key in Object){
    throw new Error("Please don't extend the native object");
}
Lewis
fonte
5

    var p =[{"username":"ordermanageadmin","user_id":"2","resource_id":"Magento_Sales::actions"},
{"username":"ordermanageadmin_1","user_id":"3","resource_id":"Magento_Sales::actions"}]
for(var value in p) {
    for (var key in value) {
        if (p.hasOwnProperty(key)) {
            console.log(key + " -> " + p[key]);
        }
    }
}

senthil
fonte
json = [{"key1":"value1","key2":"value2"},{"key1":"value3","key2":"value4"}] for (var i = 0; i < json.length; i++) { for (var key in json[i]) { if (json[i].hasOwnProperty(key)) { console.log(key + " -> " + json[i][key]); } } }
Marek Bernad
5

Usando um for-ofonObject.keys()

Gostar:

let object = {
   "key1": "value1"
   "key2": "value2"
   "key3": "value3"
};

for (var key of Object.keys(p)) {
   console.log(key + " : " + object[key])
}
Nicolas Cabanas
fonte
4

Se você quiser iterar também sobre propriedades não enumeráveis , poderá usar Object.getOwnPropertyNames(obj)para retornar uma matriz de todas as propriedades (enumeráveis ​​ou não) encontradas diretamente em um determinado objeto.

var obj = Object.create({}, {
  // non-enumerable property
  getFoo: {
    value: function() { return this.foo; },
    enumerable: false
  }
});

obj.foo = 1; // enumerable property

Object.getOwnPropertyNames(obj).forEach(function (name) {
  document.write(name + ': ' + obj[name] + '<br/>');
});

Dheeraj Vepakomma
fonte
2
Isso é fantástico, obrigado por postar esta resposta. Eu precisava examinar um Errorobjeto e não conseguia _.forIn(err)acessar as propriedades em um loop ou em uma chamada. Usar Object.getOwnPropertyNames(err)me permitiu acessar todas as partes do Errorque eu não conseguia obter antes. Obrigado!
Pierce
4

Se alguém precisar fazer um loop através de arrayObjects com a condição :

var arrayObjects = [{"building":"A", "status":"good"},{"building":"B","status":"horrible"}];

for (var i=0; i< arrayObjects.length; i++) {
  console.log(arrayObjects[i]);
  
  for(key in arrayObjects[i]) {      
    
      if (key == "status" && arrayObjects[i][key] == "good") {
        
          console.log(key + "->" + arrayObjects[i][key]);
      }else{
          console.log("nothing found");
      }
   }
}

Tadas V.
fonte
4

Considerando o ES6, gostaria de adicionar minha própria colher de açúcar e fornecer mais uma abordagem para iterar as propriedades do objeto.

Como o objeto JS comum não é iterável apenas fora da caixa, não podemos usar o for..ofloop para iterar sobre seu conteúdo. Mas ninguém pode nos parar para torná-lo iterável .

Vamos ter bookobjeto.

let book = {
  title: "Amazing book",
  author: "Me",
  pages: 3
}

book[Symbol.iterator] = function(){

  let properties = Object.keys(this); // returns an array with property names
  let counter = 0;
  let isDone = false;

  let next = () => {
    if(counter >= properties.length){
      isDone = true;
    }
    return { done: isDone, value: this[properties[counter++]] }
  }

  return { next };
}

Desde que fizemos, podemos usá-lo desta maneira:

for(let pValue of book){
  console.log(pValue);
}
------------------------
Amazing book
Me
3

Ou, se você conhece o poder dos geradores ES6 , certamente pode tornar o código acima muito mais curto.

book[Symbol.iterator] = function *(){

  let properties = Object.keys(this);
  for (let p of properties){
    yield this[p];
  }

}

Claro, você pode aplicar esse comportamento a todos os objetos, tornando Objectiterável no prototypenível.

Object.prototype[Symbol.iterator] = function() {...}

Além disso, objetos que cumprem o protocolo iterável podem ser usados ​​com o novo operador de dispersão de recursos do ES2015 , para que possamos ler os valores das propriedades dos objetos como uma matriz.

let pValues = [...book];
console.log(pValues);
-------------------------
["Amazing book", "Me", 3]

Ou você pode usar a atribuição de desestruturação :

let [title, , pages] = book; // notice that we can just skip unnecessary values
console.log(title);
console.log(pages);
------------------
Amazing book
3

Você pode conferir o JSFiddle com todo o código que forneci acima.

Artyom Pranovich
fonte
Eu encontrei o código irá gerar os valores, mas sem chaves. É possível iterar os valores com chaves?
Pika
Sim você pode. Basta retornar "yield [key, obj [key]];" da função de gerador e use-o da seguinte forma "para (deixe [chave, valor] de {}) {}"
Artyom Pranovich 8/16/16
4

desde ES06, você pode obter os valores de um objeto como matriz com

let arrValues = Object.values( yourObject) ;

retorna a matriz dos valores do objeto e não extrai valores do Prototype !!

DOCS MDN Object.values ​​()

e para chaves (já respondidas antes de mim aqui)

let arrKeys   = Object.keys(yourObject);
yehonatan yehezkel
fonte
As respostas pedem uma solução que retorne chaves e valores.
21718 Sean Lindo
4

No script mais recente do ES, você pode fazer algo assim:

let p = {foo: "bar"};
for (let [key, value] of Object.entries(p)) {
  console.log(key, value);
}

Ankit
fonte