for...of e for...in
Esta aula explica os laços for...of e for...in em JavaScript, mostrando como iterar arrays e objetos, destacando suas diferenças fundamentais e alertando sobre pegadinhas comuns. O aluno aprenderá quando usar cada um e como evitar erros sutis.
Os laços for...of e for...in são duas formas de iterar sobre coleções em JavaScript. Embora pareçam semelhantes, eles servem a propósitos distintos e têm comportamentos diferentes que podem gerar confusão. Nesta aula, vamos explorar cada um deles, comparar seu uso e destacar as armadilhas mais comuns.
Entender a diferença entre eles é essencial para escrever código limpo e previsível. O for...of itera sobre valores de objetos iteráveis (como arrays, strings, Map, Set), enquanto o for...in itera sobre as chaves (propriedades) enumeráveis de um objeto, incluindo as herdadas da cadeia de protótipos.
Iterando arrays e objetos
O for...of é ideal para percorrer arrays e outros iteráveis. Ele fornece diretamente cada valor da coleção, sem se preocupar com índices. Veja um exemplo com array:
const frutas = ['maçã', 'banana', 'laranja'];
for (const fruta of frutas) {
console.log(fruta);
}
// maçã
// banana
// laranjaJá o for...in itera sobre as chaves de um objeto. Quando usado em um array, ele retorna os índices como strings, o que pode ser surpreendente:
const frutas = ['maçã', 'banana', 'laranja'];
for (const indice in frutas) {
console.log(indice); // '0', '1', '2'
}Para objetos literais, for...in percorre as propriedades enumeráveis, incluindo as herdadas. Exemplo:
const pessoa = { nome: 'João', idade: 30 };
for (const chave in pessoa) {
console.log(chave + ': ' + pessoa[chave]);
}
// nome: João
// idade: 30Note que for...of não funciona diretamente com objetos comuns, pois eles não são iteráveis por padrão. Para iterar sobre valores de um objeto, podemos usar Object.values() ou Object.entries():
for (const valor of Object.values(pessoa)) {
console.log(valor);
}
// João
// 30Diferença crucial entre eles
A principal diferença é que for...of acessa os valores de um iterável, enquanto for...in acessa as chaves (nomes de propriedades) de um objeto. Isso tem implicações importantes no comportamento:
for...ofsó funciona com objetos que implementam o protocolo de iteração (Symbol.iterator). Arrays, strings, Map, Set e NodeList são exemplos.for...infunciona com qualquer objeto, mas não é recomendado para arrays porque ele itera sobre índices como strings e também pode incluir propriedades adicionadas ao protótipo do Array.for...inpercorre propriedades enumeráveis herdadas, o que pode causar resultados inesperados se não for usado comhasOwnProperty.
Exemplo comparativo com um array que possui uma propriedade extra:
const arr = [10, 20, 30];
arr.propExtra = 'olá';
for (const valor of arr) {
console.log(valor); // 10, 20, 30 (ignora propExtra)
}
for (const chave in arr) {
console.log(chave); // '0', '1', '2', 'propExtra'
}Isso mostra que for...in inclui a propriedade extra, enquanto for...of não. Portanto, para arrays, prefira for...of (ou métodos como forEach).
Pegadinhas
Algumas armadilhas comuns ao usar esses laços:
- Usar
for...inem arrays: Além de incluir propriedades adicionadas, a ordem de iteração não é garantida (embora na prática seja numérica crescente para índices). Isso pode quebrar código que depende da ordem. - Iterar sobre strings:
for...ofitera sobre caracteres, enquantofor...initera sobre índices (0, 1, ...). Exemplo:
const texto = 'abc';
for (const char of texto) console.log(char); // 'a', 'b', 'c'
for (const idx in texto) console.log(idx); // '0', '1', '2'- Propriedades herdadas: Ao usar
for...inem um objeto, propriedades do protótipo podem aparecer. Por exemplo, se você estenderObject.prototype(não recomendado), elas serão listadas. Para evitar, usehasOwnProperty:
const obj = { a: 1 };
for (const chave in obj) {
if (obj.hasOwnProperty(chave)) {
console.log(chave); // apenas 'a'
}
}- Não usar
for...ofem objetos: Tentar usarfor...ofdiretamente em um objeto comum lança um erroTypeError: obj is not iterable. É necessário usarObject.keys(),Object.values()ouObject.entries(). - Confundir chave e valor: Em
for...in, a variável recebe a chave (nome da propriedade), não o valor. É comum iniciantes tentarem acessarpessoa.chaveem vez depessoa[chave].
Em resumo: use for...of para arrays, strings, Map, Set e outros iteráveis. Use for...in apenas para objetos, e com cuidado, filtrando propriedades herdadas quando necessário.
Boas práticas
- Prefira
for...ofpara iterar sobre arrays, a menos que você precise explicitamente dos índices. - Ao usar
for...in, sempre considere o uso dehasOwnPropertypara evitar propriedades do protótipo. - Evite adicionar propriedades a objetos nativos como Array.prototype, pois isso afeta laços
for...in. - Para objetos, considere usar
Object.entries()comfor...ofpara obter pares chave-valor de forma mais segura.
Referências
- MDN: for...of
- MDN: for...in
- MDN: Iteradores e geradores
- MDN: Enumerabilidade e posse de propriedades
- JavaScript.info: for...in vs for...of
- W3Schools: JavaScript For In
Exercícios
- Exercício 1: Dado o array
const numeros = [1, 2, 3, 4, 5];, usefor...ofpara imprimir o dobro de cada número no console.✓ Resposta:const numeros = [1, 2, 3, 4, 5]; for (const num of numeros) { console.log(num * 2); } - Exercício 2: Dado o objeto
const carro = { marca: 'Toyota', modelo: 'Corolla', ano: 2020 };, usefor...inpara imprimir cada chave e seu valor no console.✓ Resposta:const carro = { marca: 'Toyota', modelo: 'Corolla', ano: 2020 }; for (const chave in carro) { if (carro.hasOwnProperty(chave)) { console.log(chave + ': ' + carro[chave]); } } - Exercício 3: Explique por que usar
for...inem um array pode ser problemático. Dê um exemplo.✓ Resposta:Usarfor...inem arrays pode incluir propriedades adicionadas ao array ou herdadas do protótipo, além de iterar sobre índices como strings. Exemplo:const arr = [1, 2]; arr.prop = 'extra'; for (const key in arr) { console.log(key); // '0', '1', 'prop' } - Exercício 4: Dada a string
const palavra = 'JavaScript';, usefor...ofpara imprimir cada caractere em uma linha separada.✓ Resposta:const palavra = 'JavaScript'; for (const char of palavra) { console.log(char); } - Exercício 5: Escreva um código que use
for...ofcomObject.entries()para iterar sobre as propriedades de um objeto e imprimir chave e valor.✓ Resposta:const obj = { a: 1, b: 2 }; for (const [chave, valor] of Object.entries(obj)) { console.log(chave + ': ' + valor); }