Uma questão muito comum. Iterar sobre Arrays é uma tarefa fácil para a maioria, mas quando se trata de iterar um Objeto muitos desenvolvedores acabam se complicando e o resultado não é o esperado.
Iterar um Objeto é uma tarefa que se você ainda não passou sem duvidas, mais cedo ou mais tarde, você vai passar. Então quando o dia chegar é melhor estar preparado.
Dramatização a parte, Objetos são estruturas que guardam informações e diferentemente dos Arrays, sem nenhuma ordem específica e as chaves de um Objeto podem ser de qualquer tipo, então o método que você usa para iterar um Array não necessariamente vai funcionar para um Objeto.
Felizmente Javascript disponibiliza um monte de opções pra criar essa iteração. Nesse artigo vou mostrar 5 diferentes métodos e a eficiência de cada um para um mesmo Objeto.
Basicamente, o que eu fiz foi o seguinte: criei um Objeto simples com 10.000 entradas, e utilizei o método console.time();
para medir o tempo que cada método é executado. O tempo final é a média aritmética de 10 iterações.
O código que usei para criar o array e medir os tempos é esse:
let obj = {};
for (let i = 0; i < 10000; i++) {
obj['key' + i] = 'val' + i;
}
/*
{ key0: 'val0',
key1: 'val1',
key2: 'val2',
key3: 'val3',
key4: 'val4',
key5: 'val5',
.
.
.
*/
console.time("Object Iteration Time");
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
//body
}
}
console.timeEnd("Object Iteration Time");
Você pode usar o loop for..in
como mostrei ali em cima. No entanto, você também tem de se certificar que a chave é uma propriedade real do objeto, e não uma propriedade que vem do prototype
, por isso no exemplo eu uso o Object.hasOwnProperty();
.
console.time("Object Iteration Time");
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
//body
}
}
console.timeEnd("Object Iteration Time");
//2.821ms
Usando o método for..of
já conseguimos eliminar algumas linhas de código. Nesse exemplo, pelo mesmo motivo do método acima, usei o Object.keys()
para garantir o uso apenas das próprias propriedades do objeto sem as propriedades de toda a cadeia do protótipo.
console.time("Object Iteration Time");
for (let key of Object.keys(obj)) {
//body
}
console.timeEnd("Object Iteration Time");
//3.912ms
O método Array.forEach()
é classicamente usado para Arrays, mas com algumas adaptações conseguimos utilizar em Objetos também. A classe Object do Javascript oferece vários métodos uteis, um deles é o Object.keys()
, que já foi utilizado no exemplo acima. O método retorna um array dos nomes das propriedades enumeradas de um determinado objeto, desconsiderando as propriedades do prototype
. Como o objeto retorna as chaves do Objeto, para acessar os valores é simples, basta usar obj[key]
.
console.time("Object Iteration Time");
Object.keys(obj).forEach(key => {
//body
});
console.timeEnd("Object Iteration Time");
//1.972ms
Object.values()
, é também um método da classe Object, que retorna um array dos valores das propriedades (enumeradas) de um determinado objeto. Nesse caso, não temos acesso as chaves originais do objeto apenas aos valores do objeto.
console.time("Object Iteration Time");
Object.values(obj).forEach(value => {
//body
});
console.timeEnd("Object Iteration Time");
//8.360ms
O método Object.entries()
retorna um array de pares de propriedades [chave, valor]
enumerados de um objeto. Com esse método fica fácil acessar tanto as chaves quando os valores do seu objeto, você pode fazer isso usando, por exemplo, templates literais console.log(`${key}:${value}`);
.
A ordem do array retornado por Object.entries();
não depende de como o objeto é definido.
console.time("Object Iteration Time");
Object.entries(obj).forEach(([key, value]) => {
//body
});
console.timeEnd("Object Iteration Time");
//11.887ms
Bom, o resultados que obtive durante os testes foram esses mostrados na tabela.
Apesar de ser um dos mais práticos, por já te dar acesso tanto as chaves quanto aos valores o método com Object.entries()
, se mostrou ser também o método mais lento.
Método | Tempo médio |
forEach() como Object.keys() | 1.972ms |
for..in com Object.hasOwnProperty() | 2.821ms |
for..of com Object.keys() | 3.912ms |
forEach() com Objects.values() | 8.360ms |
forEach() com Object.entries() | 11.887ms |
E o campeão em performance ficou com o terceiro método que mostrei na lista. Ele tem a desvantagem de precisar usar o obj[key]
(assim como os métodos 1 e 2) para acessar os valores. Se performance for algo crucial no seu projeto, ou se você trabalha com objetos grandes talvez seja o mais adequado.
Em fim, cada projeto pode demandar uma implementação diferente para resolver esse problema, então cabe a você desenvolvedor, saber o que se encaixa melhor no seu projeto. Até a próxima
Deixe um comentário