Iteradores são estruturas de dados que permitem processar uma sequência de elementos com mais eficiência. Este tutorial o ajudará a aprender sobre o que são iteradores JavaScript e como descobrir se algo é um iterador. Você também aprenderá sobre os tipos existentes de iteradores, seus consumidores e como trabalhar com eles.
Uma rápida introdução aos iteradores JavaScript
Um iterador é um tipo de estrutura de dados. É uma coleção de elementos. Dois exemplos dessas coleções são strings e arrays. O primeiro, string é uma coleção de caracteres. O segundo, array é uma coleção de itens. Dito isso, nem toda coleção é um iterador.
Para que uma coleção seja um iterador, ela deve estar em conformidade com a especificação da Iterable
interface. Essa interface diz que as coleções devem implementar um método Symbol.iterator . Isso significa que esse método deve estar disponível no objeto da coleção. Este método, quando invocado, retorna um objeto Iterator .
Este Iterator
objeto contém um método chamado next()
. Este método retorna um objeto com duas propriedades value
e done
. A value
propriedade contém o item da coleção que está atualmente na sequência de iteração. O done
é um booleano que informa se a iteração está no final.
Podemos usar esse next()
método para iterar na coleção de maneira controlada. Ao contrário do loop for ou do método map, em que não podemos parar e retomar a iteração, os iteradores JavaScript nos permitem fazer isso. Eles nos permitem obter cada item da coleção, para retomar a iteração, quando quisermos.
// Create an array:
const list = [1, 3, 5, 7, 9]
// Create iterator for "list" array:
const listIterator = list[Symbol.iterator]()
// Log the iterator object:
console.log(listIterator)
// Output:
// Iterator [Array Iterator] { __proto__: { next: ƒ next() } }
// Try next() method:
listIterator.next()
// Output:
// { value: 1, done: false }
listIterator.next()
// Output:
// { value: 3, done: false }
listIterator.next()
// Output:
// { value: 5, done: false }
listIterator.next()
// Output:
// { value: 7, done: false }
listIterator.next()
// Output:
// { value: 9, done: false }
listIterator.next()
// Output:
// { value: undefined, done: true }
Tipos de iteradores JavaScript
Atualmente, existem quatro tipos de dados em JavaScript que são iteráveis. Esses tipos iteráveis são strings, arrays, mapas e conjuntos.
Cordas
A ideia de que a string pode ser iterável pode parecer estranha. No entanto, é verdade. Podemos validar isso com um teste simples. Se string for iterável, deve ter o método Symbol.iterator . Se invocarmos esse método, devemos obter o objeto iterador. Com este objeto, devemos também obter o next()
método.
// Create a string and iterator object for it:
const str = 'It worked'
const strIterator = str[Symbol.iterator]()
// Iterate over individual characters with next():
strIterator.next()
// Output:
// { value: 'I', done: false }
strIterator.next()
// Output:
// { value: 't', done: false }
strIterator.next()
// Output:
// { value: ' ', done: false }
strIterator.next()
// Output:
// { value: 'w', done: false }
// Iterate over the string using for...of loop:
for (const char of str) {
console.log(char);
}
// Output:
// 'I'
// 't'
// ' '
// 'w'
// 'o'
// 'r'
// 'k'
// 'e'
// 'd'
Matrizes
Arrays são o segundo tipo iterável. Novamente, podemos testar isso usando o método e o loop Symbol.iteratorfor...of
.
// Create an array and iterator object for it:
const names = ['Josh', 'Howard', 'Lucy', 'Victoria']
const namesIterator = names[Symbol.iterator]()
// Iterate over individual items with next():
namesIterator.next()
// Output:
// { value: 'Josh', done: false }
namesIterator.next()
// Output:
// { value: 'Howard', done: false }
namesIterator.next()
// Output:
// { value: 'Lucy', done: false }
namesIterator.next()
// Output:
// { value: 'Victoria', done: false }
// Iterate over the array using for...of loop:
for (const name of names) {
console.log(name);
}
// Output:
'Josh'
'Howard'
'Lucy'
'Victoria'
Mapas
O terceiro tipo iterável é o objeto Map . Com o Maps, podemos iterar seus pares de chave e valor.
// Create a Map and iterator object for it:
const map = new Map()
map.set('name', 'Tony Stark')
map.set('alias', 'Iron Man')
map.set('reality', 'Earth-616')
map.set('education', 'MIT')
const mapIterator = map[Symbol.iterator]()
// Iterate over individual items with next():
mapIterator.next()
// Output:
// { value: [ 'name', 'Tony Stark' ], done: false }
mapIterator.next()
// Output:
// { value: [ 'alias', 'Iron Man' ], done: false }
mapIterator.next()
// Output:
// { value: [ 'reality', 'Earth-616' ], done: false }
mapIterator.next()
// Output:
// { value: [ 'education', 'MIT' ], done: false }
// Iterate over the Map using for...of loop:
for (const [key, value] of map) {
console.log(`${key}: ${value}`);
}
// Output:
'name: Tony Stark'
'alias: Iron Man'
'reality: Earth-616'
'education: MIT'
Jogos
O quarto e último tipo iterável é o objeto Set . Set
objetos são semelhantes a matrizes. A principal diferença entre a Set
e um array é que Set
não permite valores duplicados. Ao tentar adicionar valor duplicado, Set
irá manter apenas a primeira ocorrência do valor e ignorar a segunda.
// Create a map and iterator object for it:
const set = new Set(['north', 'east', 'west', 'south'])
const setIterator = set[Symbol.iterator]()
// Iterate over individual items with next():
setIterator.next()
// Output:
// { value: 'north', done: false }
setIterator.next()
// Output:
// { value: 'east', done: false }
setIterator.next()
// Output:
// { value: 'west', done: false }
setIterator.next()
// Output:
// { value: 'south', done: false }
// Iterate over the Set using for...of loop:
for (const item of set) {
console.log(item);
}
// Output:
'north'
'east'
'west'
'south'
Consumidores iteráveis e trabalhando com tipos iteráveis
Esses são os quatro tipos iteráveis com os quais podemos trabalhar em JavaScript. A próxima pergunta é: como podemos usá-los ou consumi-los. Existem quatro consumidores populares que nos permitem “consumir” iteráveis. Esses consumidores são: for...of
loop, atribuição de desestruturação, operador de propagação e Array.from()
.
para … de loop
A primeira maneira de iterar sobre iteradores JavaScript é usando o for...of
loop. A desvantagem do for...of
loop é que ele não nos dá muito controle sobre a iteração. No entanto, se tudo o que precisamos é recuperar cada item da coleção, ele fará o trabalho.
// Array:
const numbers = [2, 4, 6]
for (const num of numbers) {
console.log(num)
}
// Output:
// 2
// 4
// 6
// String:
const word = 'Root'
for (const char of word) {
console.log(char)
}
// Output:
// 'R'
// 'o'
// 'o'
// 't'
// Map:
const map = new Map([
['name', 'Joe'],
['age', 33],
])
for (const [key, val] of map) {
console.log(`${key}: ${val}`)
}
// Output:
// 'name: Joe'
// 'age: 33'
// Set:
const set = new Set(['C++', 'Assembly', 'JavaScript', 'C++'])
for (const language of set) {
console.log(language)
}
// Output:
// 'C++'
// 'Assembly'
// 'JavaScript'
Atribuição de reestruturação
Uma maneira rápida de recuperar itens de iteradores JavaScript é usando atribuição de desestruturação . Com a desestruturação, podemos recuperar qualquer item de que precisamos, um único item por vez ou vários itens de uma vez.
// Array:
const genres = ['rock', 'hip hop', 'r&b', 'metal', 'soul']
// Destructuring assignment:
const [ first, second, ...rest ] = genres
console.log(first)
// Output:
// 'rock'
console.log(second)
// Output:
// 'hip hop'
console.log(rest)
// Output:
// [ 'r&b', 'metal', 'soul' ]
// String:
const word = 'Recursion'
// Destructuring assignment:
const [first, second, third, ...rest] = word
console.log(first)
// Output:
// 'R'
console.log(second)
// Output:
// 'e'
console.log(third)
// Output:
// 'c'
console.log(rest)
// Output:
// [ 'u', 'r', 's', 'i', 'o', 'n' ]
// Map:
const map = new Map([
['water', 'fire'],
['white', 'black'],
['left', 'right'],
])
// Destructuring assignment:
const [start, middle, end] = map
console.log(start)
// Output:
// [ 'water', 'fire' ]
console.log(middle)
// Output:
// [ 'white', 'black' ]
console.log(end)
// Output:
// [ 'left', 'right' ]
// Set:
const set = new Set([1, 33, 777, 9999])
// Destructuring assignment:
const [ first, second, ...rest ] = set
console.log(first)
// Output:
// 1
console.log(second)
// Output:
// 33
console.log(rest)
// Output:
// [ 777, 9999 ]
Operador Spread
O operador Spread oferece uma maneira rápida e simples de iterar sobre o tipo iterável e transformá-lo em um array. Isso não será útil ao trabalhar com matrizes. Ainda pode ser útil ao lidar com mapas, strings e também conjuntos.
// String:
const word = 'closure'
// Spread:
const wordSpread = [...word]
console.log(wordSpread)
// Output:
// [
// 'c', 'l', 'o',
// 's', 'u', 'r',
// 'e'
// ]
// Map:
const map = new Map([
['fruit', 'apple'],
['thatGreenThing', 'kale'],
['beverage', 'tea']
])
// Spread:
const mapSpread = [...map]
console.log(mapSpread)
// Output:
// [
// [ 'fruit', 'apple' ],
// [ 'thatGreenThing', 'kale' ],
// [ 'beverage', 'tea' ]
// ]
// Set:
const set = new Set(['Halo', 'Quake', 'NFS', 'C&C'])
// Spread:
const setSpread = [...set]
console.log(setSpread)
// Output:
// [ 'Halo', 'Quake', 'NFS', 'C&C' ]
Array.from ()
Junto com o operador de propagação, Array.from()
também nos permite transformar qualquer iterável em um array. Tudo o que precisamos fazer é passar o iterável como um argumento para o from()
método.
// String:
const word = 'iterable'
// Spread:
const wordArray = Array.from(word)
console.log(wordArray)
// Output:
// [
// 'i', 't', 'e',
// 'r', 'a', 'b',
// 'l', 'e'
// ]
// Map:
const map = new Map([
[1, 1],
[2, 10],
[3, 11],
[4, 100]
])
// Spread:
const mapArray = Array.from(map)
console.log(mapArray)
// Output:
// [ [ 1, 1 ], [ 2, 10 ], [ 3, 11 ], [ 4, 100 ] ]
// Set:
const set = new Set(['BTC', 'ETH', 'ADA', 'EOS'])
// Spread:
const setArray = [...set]
console.log(setArray)
// Output:
// [ 'BTC', 'ETH', 'ADA', 'EOS' ]
Conclusão: Uma introdução simples aos iteradores JavaScript
Iteradores e iteráveis podem ser úteis quando precisamos de uma coleção sobre a qual possamos iterar de maneira controlada. Neste tutorial, vimos o que são iteradores JavaScript, quais tipos de iteradores estão disponíveis e como trabalhar com eles, usando o for...of
loop, atribuição de desestruturação, operador de propagação e Array.from()
.