La iteración se refiere al proceso de extraer continuamente datos de un conjunto de datos en un orden determinado.
Entonces, ¿cuál es la diferencia entre iteración y recorrido?
En JavaScript, un iterador es un objeto que puede llamar next
método para implementar la iteración. devuelve un Un objeto con dos propiedades.
value
: el siguiente valor del objeto iterabledone
: indica si se han recuperado todos los datos. false
significa que todavía hay datos, true
significa que no habrá datos más adelante.para generar iteradores a través de la función de fábrica de iteradores Symbol.iterator
en el objeto iterable.
constante arr = []console.log(arr)
ajuste constante = [1, 2, 3] const iter1 = arr[Symbol.iterator]() // Genera un iterador a través de la función de fábrica de iteradores `Symbol.iterator`. consola.log(iter1) consola.log(iter1.siguiente()) consola.log(iter1.siguiente()) consola.log(iter1.siguiente()) consola.log(iter1.siguiente()) console.log('%c%s', 'color:rojo;tamaño de fuente:24px;', '==================') const mimapa = nuevo mapa() mymap.set('nombre', 'clz') mimapa.set('edad', 21) const iter2 = mymap[Symbol.iterator]() // Genera un iterador a través de la función de fábrica de iteradores `Symbol.iterator`. consola.log(iter2) consola.log(iter2.siguiente()) consola.log(iter2.siguiente()) consola.log(iter2.siguiente())
Se puede encontrar que el iterador se completa después de tomar el último valor, es decir, cuando el siguiente value
del iterador no está undefined
.
Sin embargo, la declaración anterior no es muy precisa. No se completa cuando el siguiente value
del iterador no está undefined
. También debe determinar si realmente no hay ningún valor o si hay un valor undefined
en el objeto iterable. Si hay un valor en el objeto iterable que no está undefined
, no se completará en este momento.
constante arr = [1, 2, 3, indefinido] const iter1 = arr[Symbol.iterator]() // Genera un iterador a través de la función de fábrica de iteradores `Symbol.iterator`. consola.log(iter1) consola.log(iter1.siguiente()) consola.log(iter1.siguiente()) consola.log(iter1.siguiente()) consola.log(iter1.siguiente()) consola.log(iter1.siguiente())
pueden llamar a la función de fábrica de iteradores varias veces sin interferir entre sí para generar múltiples iteradores. Cada iterador representa un recorrido ordenado único del objeto iterable. Los diferentes iteradores no interfieren entre sí y sólo atravesarán objetos iterables de forma independiente .
ajuste constante = [1, 2, 3] const iter1 = arr[Symbol.iterator]() // Genera un iterador a través de la función de fábrica de iteradores `Symbol.iterator`. const iter2 = arr[Símbolo.iterador]() console.log('Iterador1:', iter1.siguiente()) console.log('Iterator2:', iter2.next()) console.log('Iterador1:', iter1.siguiente()) console.log('Iterator2:', iter2.next())
const arr = [1, 2, 3] const iter = arr[Símbolo.iterador]() para (const i de iter) { console.log(i) // Salida 1, 2, 3 en secuencia }
Si el objeto iterable se modifica durante la iteración, el resultado obtenido por el iterador también se modificará.
ajuste constante = [1, 2, 3] consola.log(arr) const iter = arr[Símbolo.iterador]() consola.log(iter.siguiente()) arreglo[1] = 999 consola.log(iter.siguiente()) consola.log(iter.siguiente())
Cuando iteramos hasta done: true
, ¿se informará un error al llamar next
o no se devolverá nada?
Sin embargo, no, el iterador estará en un estado completado pero no completado done: true
significa que se ha completado, pero aún se puede llamar next
en el futuro, aunque el resultado siempre será { value: undefined, done: true }
. Por eso se dice hecho pero no hecho .
ajuste constante = [1, 2, 3] const iter = arr[Símbolo.iterador]() consola.log(iter.siguiente()) consola.log(iter.siguiente()) consola.log(iter.siguiente()) consola.log(iter.siguiente()) consola.log(iter.siguiente()) consola.log(iter.siguiente())
Del ejemplo anterior, podemos saber que el iterador se genera a través de la función de fábrica de iteradores Symbol.iterator
, por lo que necesitamos implementar una función de fábrica de iteradores y luego el iterador puede llamar al next
método, por lo que también necesita implementar un método next
. En cuanto a la función de fábrica de iteradores, en realidad devuelve la this
directamente.
Ejemplo de contador:
clase Contador { constructor(límite) { este.recuento = 1 this.limit = límite } próximo() { if (este.recuento <= este.límite) { devolver { hecho: falso, valor: this.count++ } } demás { devolver {hecho: verdadero, valor: indefinido} } } [Símbolo.iterador]() { devolver esto }}
contador constante = nuevo contador(3) const iter = contador[Símbolo.iterador]() consola.log(iter.siguiente()) consola.log(iter.siguiente()) consola.log(iter.siguiente()) consola.log(iter.siguiente()) consola.log(iter.siguiente())
A primera vista, no hay ningún problema, pero si usamos for-of
para atravesar, podemos encontrar el problema.
contador constante = nuevo contador (3) para (sea i del contador) { console.log(i)}console.log('Otra iteración:')for (sea i del contador) { consola.log(i)}
El uso de for-of
también lo hace desechable. Esto se debe a que count
es una variable de esta instancia, por lo que se usa la misma variable en ambas iteraciones. Sin embargo, después del primer bucle de la variable, ha excedido el límite, por lo que no obtendrá nada al usar for-of
. de nuevo. El resultado fue.
Puede colocar la variable count
en un cierre y luego devolver el iterador a través del cierre, de modo que cada iterador creado corresponda a un nuevo contador.
clase contador { constructor(límite) { this.limit = límite } [Símbolo.iterador]() { vamos a contar = 1 límite constante = this.limit return { // La función de fábrica de iteradores debe devolver un objeto con un método siguiente, porque la iteración en realidad se implementa llamando al método siguiente next() { si (recuento <= límite) { devolver { hecho: falso, valor: contar ++ } } demás { devolver {hecho: verdadero, valor: indefinido} } } } }}
Prueba
de contador constante = nuevo contador (3) para (sea i del contador) { console.log(i)}console.log('Otra iteración:')for (sea i del contador) { consola.log(i)}
es como usar for-of
. Cuando el iterador termina temprano, el iterador llamará inteligentemente al método return
next
[Símbolo.iterador]() { vamos a contar = 1 límite constante = this.limit return { // La función de fábrica de iteradores debe devolver un objeto con un método siguiente, porque la iteración en realidad se implementa llamando al método siguiente next() { si (recuento <= límite) { devolver { hecho: falso, valor: contar ++ } } demás { devolver {hecho: verdadero, valor: indefinido} } }, devolver() { console.log('Terminación anticipada del iterador') devolver {hecho: verdadero} } }}
Prueba
de contador constante = nuevo contador (5) para (sea i del contador) { si (yo === 3) { romper; } consola.log(i)}
Si el iterador no está cerrado, puede continuar iterando desde donde lo dejó . Los iteradores de matriz no se pueden cerrar.
const arr = [1, 2, 3, 4, 5]const iter = arr[Símbolo.iterador]()iter.return = función () { console.log('Salir temprano del iterador') devolver { hecho: verdadero }}para (const i de iter) { consola.log(i) si (yo === 2) { romper }}para (const i de iter) { consola.log(i)}