Continuamos viendo las novedades que nos presenta ES6. En esta entrada, veremos los generadores. Los generadores son funciones especiales que nos permiten pausar la ejecución y volver a reanudar la ejecución desde donde nos habíamos quedado.
Antes de nada vamos a ver su sintaxis. Porque aunque se declara y llama de manera parecida a las funciones, no es igual.
1 2 3 |
function* generatorTest() { // código } |
El código de arriba es un ejemplo de como se declararía un generador. Como vemos, se declara como una función, pero entre el function y el nombre de la función, se pone un *. En realidad, da igual que lo pongas pegado a function , entre dos espacios, pegado al nombre de la función o sin espacios. Así que puedes ponerlo como te sea más cómodo, pero si quieres declarar un generador tienes que ponerlo. 🙂
Cómo ya he dicho anteriormente, los generadores son funciones que pueden ser pausadas y esto se hace con la instrucción yield . yield funciona como si fuese un return, pero para los generadores.
1 2 3 4 |
function* generatorTest() { yield 1; yield "string"; } |
Ahora, vamos a ver como se llamaría, porque pasa lo mismo que con la declaración. Es parecida, pero no igual.
1 2 3 4 5 |
const generatorItr = generatorTest(); console.log(generatorItr.next()); // { value: 1, done: false } console.log(generatorItr.next()); // { value: 'string', done: false } console.log(generatorItr.next()); // { value: undefined, done: true |
En el código anterior, vemos como se llama a un generador. Primero de todo, llamamos a la función declarada anteriormente, que si te fijas no se está ejecutando en este momento, y asignamos el iterador que nos devuelve a una constante. Después, ejecutamos el método .next() y es aquí cuando realmente se está ejecutando la función, pero cuando se encuentra un yield se pausa. Cuando volvemos a ejecutar el método .next() vuelve a ejecutarse desde donde se había quedado, hasta que se encuentre el próximo yield . Así funcionan los generadores.
Lo que nos devuelve el método .next() es un objeto con el valor (value) devuelto con el yield y nos dice si ya ha finalizado el iterador (done) con un true o false. Cuando finaliza, nos devuelve que el value es undefined y el done es true.
El ejemplo anterior puedes verlo en vivo aquí: https://repl.it/@vreaxe/ES6-Generadores
Vamos a ver un ejemplo completo con un generador. Por ejemplo, con una función muy sencilla que comprueba si un string es un palíndromo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
// función para comprobar si un string es palíndromo function checkPalindrome(string) { const reversedString = string.split('').reverse().join(''); return string === reversedString; } // generador function* generator(arrayStrings) { for (string of arrayStrings) { yield checkPalindrome(string); } } const generatorItr = generator(['non', 'test', 'noon',]); console.log(generatorItr.next()); // { value: true, done: false } console.log(generatorItr.next()); // { value: false, done: false } console.log(generatorItr.next()); // { value: true, done: false } console.log(generatorItr.next()); // { value: undefined, done: true } |
Ver código anterior en vivo: https://repl.it/@vreaxe/ES6-Ejemplo-generador
El funcionamiento del generador es el mismo explicado anteriormente. Le pasamos un array de strings al generador, se recorre este array con un bucle for-of, se comprueba si el string es palíndromo y devuelve con yield el valor que devuelve la función checkPalindrome .