EcmaScript 6

Una función generadora es aquella que devuelve un generador. Si no has leído el artículo anterior estarás pensando: “Pues me he quedado igual” 😂, así que te recomiendo que le des una vuelta para ir poniéndote en situación.

Si pasamos a hacer una definición más formal:

Una función generadora es aquella que actúa como un iterador con distintos puntos de salida. Esto es, al instanciarla, podemos ir llamando al método next() del iterador, que nos devolverá un valor y el estado para poder saber si hay más valores en ese iterador.

Esto lo vamos a entender mejor con un ejemplo:

function* simpleGenerator() {
  yield 1;
  yield 2;
  yield 3;
}

const generator1 = simpleGenerator();

// Probemos a meter el generador en un for..of
for (const value of generator1) {
  console.log(value);
  // Imprimirá por consola en cada iteración:
  // 1
  // 2
  // 3
  // Al llegar al 3, como no hay más valores sale del bucle
}

const generator2 = simpleGenerator();

// Al funcionar como un iterador también podemos llamar al método next()
console.log(generator2.next()); // {value: 1, done: false}
console.log(generator2.next()); // {value: 2, done: false}
console.log(generator2.next()); // {value: 3, done: false}
console.log(generator2.next()); // {value: undefined, done: true}

En el ejemplo anterior, lo primero que habréis apreciado es que tras function aparece el carácter *. Esto indica que la función es de tipo generadora. Si no usáramos el asterisco, ya no actuaría como tal y tampoco podríamos utilizar la palabra clave yield dentro de ella. Pero, ¿qué hace yield? Pues al usarla actúa como un return un tanto especial, ya que deja un marcador a la última posición en la que se llamó. De forma que al llamar al iterador con .next(), se continuará por la línea siguiente al último ejecutado.

Tendríamos un flujo como el siguiente:

En el ejemplo hemos visto un caso muy sencillo y poco práctico. Pero doblemos la apuesta y pasemos a algo más complicadillo:

function* fibonacci() {
  yield 0;
  yield 1;

  let previous = 0;
  let current = 1;

  while (Number.isFinite(current)) {
    const result = previous + current;
    previous = current;
    current = result;
    yield result;
  }
}

const fibonacciIterator = fibonacci();
for (let index = 0; index < 10; ++index) {
  console.log(fibonacciIterator.next().value);
}

// Lo anterior imprimirá por pantalla:        
// 0
// 1
// 1
// 2
// 3
// 5
// 8
// 13
// 21
// 34

En esta ocasión tenemos un generador de números de Fibonnaci. Lo más interesante de este ejemplo, es que se puede comprobar como las variables internas a la función guardan sus valores en cada paso del iterador.

Para terminar, si en lugar de hacer un bucle con los 10 primeros números, llegáramos a dejarlo en un bucle for...of, éste terminaría cuando el valor actual sea Infinity.

const fibonacciIterator = fibonacci();
for (const value of fibonacciIterator) {
  console.log(val);
}

// Terminaría imprimiendo algo tan bonico como:

// ...
// 7.283601309201629e+306
// 1.1785114478791467e+307
// 1.9068715787993096e+307
// 3.085383026678456e+307
// 4.992254605477766e+307
// 8.077637632156222e+307
// 1.3069892237633987e+308
// Infinity

// Cuando la suma alcanza Infinity, ya no entramos en el bucle y el iterador indicaría que ha finalizado.

Y con este artículo terminamos con los iteradores en JavaScript. Como siempre cualquier duda que tengáis podéis dejarla en los comentarios 😉.

Comparte este artículo con quien quieras
Iteradores en JavaScript. Parte 1. Symbol.iterator
11 cosas que quizás no sabías de JavaScript

Leave a Comment

Your email address will not be published. Required fields are marked *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.