JavaScript para todos: Iteradores — Smashing Magazine

PUBLICIDADE

Ei, meu nome é Mat, mas “Wilto” também funciona – estou aqui para lhe ensinar JavaScript. Bem, não aqui-aqui; tecnicamente, estou na casa de Piccalil.li JavaScript para todos curso para ensinar JavaScript. A seguir está um trecho do Iteráveis ​​e Iteradores módulo: a lição sobre Iteradores.

Iteradores são um dos tópicos mais confusos do ponto de vista linguístico do JavaScript, navegando facilmente acima do que já é um padrão bastante alto. Há iteráveis – array, Set, Map e string – todos seguindo o protocolo iterável. Para seguir esse protocolo, um objeto deve implementar o interface iterável. Na prática, isso significa que o objeto precisa incluir um [Symbol.iterator]() método em algum lugar em sua cadeia de protótipos. O protocolo iterável é um dos dois protocolos de iteração. O outro protocolo de iteração é o protocolo iterador.

Veja o que quero dizer sobre isso ser linguisticamente complicado? Os iteráveis ​​implementam a interface de iteração iterável e os iteradores implementam a interface de iteração do iterador! Se você puder dizer isso cinco vezes rápido, então você entendeu a essência; fácil, certo?

Não, escute, quando você chegar ao final desta lição, prometo que não será tão confuso quanto pode parecer, especialmente com o contexto que você terá nas lições que a precedem.

Um iterável object segue o protocolo iterável, o que significa apenas que o objeto possui um método convencional para fazer iteradores. Os elementos que ele contém podem ser repetidos com forof.

Um iterador objeto segue o protocolo do iterador e os elementos que ele contém podem ser acessados sequencialmenteum de cada vez.

Para reiterar — um jogo de palavras pelo qual não me perdoo, nem espero que você me perdoe — um iterador o objeto segue o protocolo do iterador e os elementos que ele contém podem ser acessados sequencialmenteum de cada vez. O protocolo Iterator define uma maneira padrão de produzir uma sequência de valores e, opcionalmente, return um valor depois que todos os valores possíveis tiverem sido gerados.

Para seguir o protocolo do iterador, um objeto precisa – você adivinhou – implementar o interface do iterador. Na prática, isso significa mais uma vez que um determinado método deve estar disponível em algum lugar da cadeia de protótipos do objeto. Neste caso, é o next() método que avança pelos elementos que contém, um de cada vez, e retorna um objeto cada vez que esse método é chamado.

Para atender aos critérios da interface do iterador, o objeto retornado deve conter duas propriedades com chaves específicas: uma com a chave valuerepresentando o valor do elemento atual, e um com a chave doneum valor booleano que nos informa se o iterador avançou além do elemento final na estrutura de dados. Essa não é uma frase estranha que a equipe editorial deixou escapar: o valor disso done propriedade é true somente quando uma chamada para next() resulta em uma tentativa de acessar um elemento além o elemento final no iterador, não ao acessar o elemento final no iterador. Novamente, muito impresso, mas fará mais sentido quando você vê-lo em ação.

Você já viu um exemplo de iterador integrado antes, embora brevemente:

const theMap = new Map([ [ "aKey", "A value." ] ]);

console.log( theMap.keys() );
// Result: Map Iterator { constructor: Iterator() }

É isso mesmo: embora o próprio objeto Map seja iterável, os métodos integrados do Map keys(), values()e entries() todos retornam objetos Iterator. Você também deve se lembrar que eu passei por aqueles que usavam forEach (uma adição relativamente recente ao idioma). Usado dessa forma, um iterador é indistinguível de um iterável:

const theMap = new Map([ [ "key", "value " ] ]);

theMap.keys().forEach( thing => {
  console.log( thing );
});
// Result: key

Todos os iteradores são iteráveis; todos eles implementam a interface iterável:

const theMap = new Map([ [ "key", "value " ] ]);

theMap.keys()[ Symbol.iterator ];
// Result: function Symbol.iterator()

E se você está irritado com a crescente indefinição da linha entre iteradores e iteráveis, espere até ver esse vídeo candidato das “dez principais traições de anime”: vou demonstrar como interagir com um iterador usando um array.

“BOO”, você certamente chora, tendo sido tão traído por um de seus amigos mais antigos e indexados. “Array é uma iteraimpossívelnão uma iterapara!” Vocês estão certos em gritar comigo em geral e certos sobre array em específico – um array é um iterável, não um iterador. Na verdade, embora todos os iteradores sejam iteráveis, nenhum dos iteráveis ​​integrados é iterador.

No entanto, quando você chama isso [ Symbol.iterator ]() método – aquele que define um objeto como iterável – retorna um objeto iterador criado a partir de uma estrutura de dados iterável:

const theIterable = [ true, false ];
const theIterator = theIterable[ Symbol.iterator ]();

theIterable;
// Result: Array [ true, false ]

theIterator;
// Result: Array Iterator { constructor: Iterator() }

O mesmo vale para Set, Map e – sim – até strings:

const theIterable = "A string."
const theIterator = theIterable[ Symbol.iterator ]();

theIterator;
// Result: String Iterator { constructor: Iterator() }

O que estamos fazendo aqui manualmente — criando um iterador a partir de um iterável usando %Symbol.iterator% – é precisamente como os objetos iteráveis ​​funcionam internamente e por que eles precisam implementar %Symbol.iterator% a fim de ser iteráveis. Sempre que você faz um loop em um array, na verdade você está fazendo um loop em um iterador criado a partir desse array. Todos os iteradores integrados são iterável. Todos os iteráveis ​​integrados podem ser usados ​​para criar iteradores.

Alternativamente – de preferênciaaté mesmo, já que não exige que você esbarre %Symbol.iterator% diretamente – você pode usar o integrado Iterator.from() método para criar um objeto iterador a partir de qualquer iterável:

const theIterator = Iterator.from([ true, false ]);

theIterator;
// Result: Array Iterator { constructor: Iterator() }

Você se lembra de como mencionei que um iterador deve fornecer um next() método (que retorna um objeto muito específico)? Chamando isso next() O método percorre os elementos que o iterador contém, um de cada vez, com cada chamada retornando uma instância desse objeto:

const theIterator = Iterator.from([ 1, 2, 3 ]);

theIterator.next();
// Result: Object { value: 1, done: false }

theIterator.next();
// Result: Object { value: 2, done: false }

theIterator.next();
// Result: Object { value: 3, done: false }

theIterator.next();
// Result: Object { value: undefined, done: true }

Você pode pensar nisso como uma forma de travessia mais controlada do que o tradicional “dar corda e ver passar” for loops com os quais você provavelmente está acostumado – um método de acessar elementos, uma etapa de cada vez, conforme necessário. Concedido, você não ter percorrer um iterador dessa maneira, já que eles têm seus próprios Iterator.forEach método, que funciona exatamente como você esperaria – até certo ponto:

const theIterator = Iterator.from([ true, false ]);

theIterator.forEach( element => console.log( element ) );
/* Result:
true
false
*/

Mas há outra grande diferença entre iteráveis ​​e iteradores que ainda não abordamos e, para mim, isso realmente ajuda muito a tornar linguística sentido dos dois. Talvez você precise me agradar um pouco aqui, no entanto.

Veja, um objeto iterável é um objeto iterável. Não, ouça, fique comigo: você pode iterar sobre um Array e, quando terminar, ainda poderá iterar sobre esse Array. É, por definição, um objeto que pode ser iterado; é a natureza essencial de um iterável ser iterável:

const theIterable = [ 1, 2 ];

theIterable.forEach( el => {
  console.log( el );
});
/* Result:
1
2
*/

theIterable.forEach( el => {
  console.log( el );
});
/* Result:
1
2
*/

De certa forma, um objeto iterador representa o singular agir de iteração. Interno a um iterável, é o mecanismo pelo qual o iterável é iterado, cada vez que a iteração é executada. Como um objeto iterador independente — quer você o percorra usando o método next método ou loop sobre seus elementos usando forEach – uma vez iterado, esse iterador é pretérito; isso é iterado. Por manterem um estado interno, a natureza essencial de um iterador é ser iterado, singular:

const theIterator = Iterator.from([ 1, 2 ]);

theIterator.next();
// Result: Object { value: 1, done: false }

theIterator.next();
// Result: Object { value: 2, done: false }

theIterator.next();
// Result: Object { value: undefined, done: true }

theIterator.forEach( el => console.log( el ) );
// Result: undefined

Isso é um ótimo trabalho quando você usa os métodos integrados do construtor Iterator para, digamos, filtrar ou extrair parte de um objeto Iterator:

const theIterator = Iterator.from([ "First", "Second", "Third" ]);

// Take the first two values from `theIterator`:
theIterator.take( 2 ).forEach( el => {
  console.log( el );
});
/* Result:
"First"
"Second"
*/

// theIterator now only contains anything left over after the above operation is complete:
theIterator.next();
// Result: Object { value: "Third", done: false }

Quando você chegar ao final de um iterador, o ato de iterá-lo estará completo. Iterado. Pretérito.

E o mesmo acontece com o seu tempo nesta lição, você pode ficar aliviado em saber. Eu sei que foi meio difícil, mas a boa notícia é: este curso é iterável, não um iterador. Esta etapa de sua iteração — esta lição — pode ter terminado, mas a natureza essencial deste curso é que você possa iterá-lo novamente. Não se preocupe em memorizar tudo isso agora – você pode voltar e revisitar esta lição a qualquer momento.

Conclusão

Mantenho o que escrevi lá, por mais surpreendente que isso seja: esta lição é complicada, mas ouça, você conseguiu isso. JavaScript for Everyone foi projetado para levar você para dentro da cabeça do JavaScript. Depois que você começar a ver como as engrenagens se encaixam – ver as impressões digitais deixadas pelas pessoas que construíram a linguagem e as decisões boas, ruins e às vezes desconcertantes que ocorreram nisso – não causa-se -ble ou -tor será capaz de ficar no seu caminho.

JavaScript para todos já está disponível e o preço de lançamento vai até meia-noite de 28 de outubro. Economize £ 60 no preço total de £ 249 e compre por £ 189! (Visualização grande)

Meu objetivo é ensinar a você o magia profunda – o como e o por que de JavaScript, usando as sintaxes que você provavelmente encontrará em seu trabalho diário, no seu ritmo e nos seus termos. Se você é novo na linguagem, sairá deste curso com uma compreensão básica de JavaScript que vale centenas de horas de tentativa e erro. Se você for um desenvolvedor júnior, terminará este curso com um conhecimento profundo que rivaliza com qualquer desenvolvedor sênior.

Espero ver você lá.

(gg, sim)

Fonte: Tecmundo, Olhar Digital, MeioBit

Mais recentes

PUBLICIDADE

WP Twitter Auto Publish Powered By : XYZScripts.com