Front End

3 jan, 2018

A diferença entre for…of e for…in

Publicidade

Com a chegada do ECMAScript 6 (2015), ganhamos o laço de iteração for…of. A ideia é que o utilizemos para iterar objetos iteráveis, ou seja, que definem em sua estrutura – através de uma função geradora, na propriedade [Symbol.iterator] – como ele deve ser percorrido. Por padrão, alguns objetos no JavaScript já são iteráveis, como é o caso do Array, Map, Set e o próprio objeto String.

Seu uso é bastante simples. Imagine que temos um array de números naturais e queremos exibir seus valores no console. Com o laço de repetição for…of, basta fazermos isso:

const numeros = [1,2,3,4,5];
for(let numero of numeros) {
  console.log(numero);
}

// resultado: 1, 2, 3, 4, 5

Bem tranquilo, certo? Mas o que acontece é que muita gente confunde esse novo tipo de laço com o já antigo laço for…in. Será que eles são a mesma coisa? Vamos colocar a prova. Vou fazer a mesma iteração do exemplo anterior, só mudando o of para in.

const numeros = [1,2,3,4,5];
for(let numero in numeros) {
  console.log(numero);
}

// resultado: 0, 1, 2, 3, 4

Espera aí, o resultado foi diferente! Mas por quê? Vamos entender o que está acontecendo. Se consultarmos a definição do laço no site do MDN, veremos que o laço for…in “interage sobre propriedades enumeradas de um objeto, na ordem original de inserção”. Na prática, isso significa que o laço enxerga as propriedades e não os seus valores.

Isso fica mais fácil de entender se tentarmos iterar esse objeto Casa que possui 3 propriedades: área, altura, andares. Repare no que acontece:

const Casa = {
  area: 1000,
  altura: 7,
  andares: 2
}

for(let prop in Casa) {
  console.log(prop);
}

// Resultado
// area
// altura
// andares

Percebeu a diferença? O laço for…of itera os valores das propriedades (neste caso), enquanto o laço for…in itera as propriedades. Mas não pense que basta alterar o in por of que este exemplo funcionará, porque é isso o que acontece:

TypeError: Casa is not iterable

O que este erro quer dizer? Assim como já comentei no início do artigo, o laço for…of procura pela propriedade [Symbol.iterator] do objeto para conseguir iterá-lo. O que este erro está nos dizendo é que ele não foi definido nesta estrutura. Para resolver este problema, podemos fazer desta maneira:

const Casa = {
  area: 1000,
  altura: 7,
  andares: 2,
  [Symbol.iterator]: function* (){
	yield this.area;
	yield this.altura;
	yield this.andares;
  }
}

Agora, sim, temos o resultado esperado:

for(let prop of Casa) {
  console.log(prop);
}

// Resultado
// 1000, 7, 2

Conclusão

Os laços for…of e for…in apesar de serem bem parecidos, fazem coisas distintas. Enquanto o primeiro procura dentro da estrutura pela propriedade [Symbol.iterator] que define como ela deve ser iterada, o segundo itera pelas propriedades enumeradas do objeto. Os objetos iteráveis por definição no JavaScript já descrevem a propriedade para que ela exiba os seus valores (ex: Map, Set, Array), mas em qualquer outro tipo de estrutura essa decisão fica por conta do desenvolvedor.

Se você gostou deste artigo ou ainda está com dúvidas, te convido a visitar este material. Lá você encontrará o meu livro Entendendo o ECMAScript 6 – Entre de cabeça no futuro do JavaScript publicado pela Casa do Código e o curso completo Entendendo o ECMAScript 6 na Udemy, publicado pela Code Prestige.

Referências

  1. https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Statements/for…in
  2. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator
  3. https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Statements/for…of