Entendiendo el patrón iterador Iterator pattern en Javascript
Feb 23, 2022

Entendiendo el patrón iterador Iterator pattern en Javascript

🚀 Entendiendo el patrón iterador (Iterator pattern) en Javascript 🚀

En este post aprenderemos cómo implementar el patrón iterador en Javascript 🟨 y en qué situaciones lo podemos usar 💻.

El patrón iterador es uno de los patrones de diseño de software más usado en Javascript y también uno de los más sencillos 😌. Es un patrón de comportamiento, ya que define cómo se comunican objetos entre sí 🔗. De él se extienden importantes aplicaciones que pueden ayudar a definir mejores arquitecturas en aplicaciones web 🌐, por lo que su uso y estudio es altamente recomendado 📚. En este post aprenderemos cómo implementarlo en Javascript y en qué situaciones lo podemos usar.

Empecemos por definir este patrón 📖. Básicamente todos hemos usado arrays de esta forma [1,2,3,4] y usualmente si queremos recorrerlo nos inclinamos rápidamente por usar una estructura cíclica como for o while 🔄, sin embargo esto hace que el código sea un poco más imperativo y menos declarativo, haciendo que no tengamos tanto control con cada dato unitario dentro del arreglo. Desde este punto es donde empieza a cobrar fuerza este patrón iterador 🌀, ya que básicamente lo que nos provee es una manera de recorrer el arreglo de una manera declarativa. El principal principio de este patrón es permitirnos recorrer colecciones de objetos de una manera que podamos decidir cuándo queremos el siguiente objeto y cuándo no 🚦. Para ello, obligatoriamente deben existir tres métodos dentro del iterador:

  1. first() --> Retorna siempre el primer objeto de la colección 🥇.
  2. next() --> Retorna el siguiente objeto de la colección si existe ➡️.
  3. current() --> Retorna el objeto actual de la colección sobre el que estamos parados 📍.

Empecemos entonces por definir una clase llamada Iterator con estos tres métodos:

// Define la clase "Iterator"
class Iterator {
  // Constructor de la clase "Iterator" que acepta un argumento "collection"
  constructor(collection) {
    // Inicializa la propiedad "index" con el valor 0
    this.index = 0;
    // Asigna el valor del argumento "collection" a la propiedad "collection" del objeto
    this.collection = collection;
  }
  // Método "first" para obtener el primer elemento de la colección
  first() {
    // Retorna el primer elemento de la colección (índice 0)
    return this.collection[0];
  }
  // Método "next" para obtener el siguiente elemento de la colección
  next() {
    // Incrementa el valor de la propiedad "index" en 1
    this.index += 1;
    // Retorna el elemento de la colección en la posición actual de "index"
    return this.collection[this.index];
  }
  // Método "current" para obtener el elemento actual de la colección
  current() {
    // Retorna el elemento de la colección en la posición actual de "index"
    return this.collection[this.index];
  }
}

Como ves, usando ES6 hemos definido una clase que permite hacer operaciones muy básicas sobre el array, pero siempre conservando cuál es el índice sobre el que está la colección en todo momento 📌. Esto nos permitirá fácilmente movernos sobre ella. Adicionalmente, aunque no es obligatorio en la implementación de este patrón, sí es altamente recomendado añadir dos métodos utilitarios más sobre la clase iterador. Estos son:

  • hasNext() —> Retorna true si hay más items disponibles en la colección ✔️.
  • reset() —> Permite reiniciar el índice para iterar de nuevo sobre la colección 🔙.

Veamos entonces cómo sería la implementación:

// Define la clase "Iterator"
class Iterator {
  // ...

  // Método "reset" para reiniciar el índice del iterador al inicio de la colección
  reset() {
    // Asigna el valor 0 a la propiedad "index" del objeto
    this.index = 0;
  }

  // Método "hasNext" para verificar si hay un siguiente elemento en la colección
  hasNext() {
    // Retorna "true" si la longitud de la colección es mayor que el índice actual más uno, de lo contrario, retorna "false"
    return this.collection.length > this.index + 1;
  }
  
  // ...
}

¡Super simple! 😄 Una vez que tu clase esté definida, puedes usar prácticamente cualquier tipo de array para construir tu iterador y operar sobre él. Veamos un ejemplo de su uso práctico usando un ciclo while:

// Crea una constante "arr" que contiene un array con los números del 1 al 5
const arr = [1, 2, 3, 4, 5];

// Crea una nueva instancia de la clase "Iterator" utilizando el array "arr" como argumento y asigna el objeto resultante a la constante "arrayIterator"
const arrayIterator = new Iterator(arr);

// Imprime en la consola el primer elemento del array utilizando el método "first" del objeto "arrayIterator"
console.log(arrayIterator.first());

// Inicia un bucle "while" que se ejecuta mientras haya un siguiente elemento en el array
while (arrayIterator.hasNext()) {
  // Imprime en la consola el siguiente elemento del array utilizando el método "next" del objeto "arrayIterator"
  console.log(arrayIterator.next());
}

De esta manera queda totalmente completo el patrón iterador. Como ves, es muy fácil implementar el patrón iterador y su utilidad es casi inmediata 🌟. A continuación, podrás observar todo el código completo de este ejemplo:

// Define la clase "Iterator"
class Iterator {
  // Constructor de la clase "Iterator" que acepta un argumento "collection"
  constructor(collection) {
    // Inicializa la propiedad "index" con el valor 0
    this.index = 0;
    // Asigna el valor del argumento "collection" a la propiedad "collection" del objeto
    this.collection = collection;
  }
  // Método "first" para obtener el primer elemento de la colección
  first() {
    // Retorna el primer elemento de la colección (índice 0)
    return this.collection[0];
  }
  // Método "next" para obtener el siguiente elemento de la colección
  next() {
    // Incrementa el valor de la propiedad "index" en 1
    this.index += 1;
    // Retorna el elemento de la colección en la posición actual de "index"
    return this.collection[this.index];
  }
  // Método "current" para obtener el elemento actual de la colección
  current() {
    // Retorna el elemento de la colección en la posición actual de "index"
    return this.collection[this.index];
  }
  // Método "reset" para reiniciar el índice del iterador al inicio de la colección
  reset() {
    // Asigna el valor 0 a la propiedad "index" del objeto
    this.index = 0;
  }
  // Método "hasNext" para verificar si hay un siguiente elemento en la colección
  hasNext() {
    // Retorna "true" si el índice actual más uno es menor que la longitud de la colección, de lo contrario, retorna "false"
    return this.index + 1 < this.collection.length;
  }
}

// Crea una constante "arr" que contiene un array con los números del 1 al 5
const arr = [1, 2, 3, 4, 5];

// Crea una nueva instancia de la clase "Iterator" utilizando el array "arr" como argumento y asigna el objeto resultante a la constante "arrayIterator"
const arrayIterator = new Iterator(arr);

// Imprime en la consola el primer elemento del array utilizando el método "first" del objeto "arrayIterator"
console.log(arrayIterator.first());

// Inicia un bucle "while" que se ejecuta mientras haya un siguiente elemento en el array
while (arrayIterator.hasNext()) {
  // Imprime en la consola el siguiente elemento del array utilizando el método "next" del objeto "arrayIterator"
  console.log(arrayIterator.next());
}

Eso es todo, espero que este post te sea de utilidad y lo puedas aplicar a algún proyecto que tengas en mente 🧠, y que simplemente te haya ayudado a entender la naturaleza del patrón iterator. Déjame un comentario si lograste implementarlo, si quieres añadir alguna otra funcionalidad o si tienes alguna duda, no dudes en dejarme un comentario en la parte de abajo ⬇️. Recuerda que si te gustó, también puedes compartir usando los links a las redes sociales en la parte de abajo 🌐.

🎯 Conclusiones 🎯

  1. El patrón iterador es una forma poderosa y declarativa de recorrer colecciones de objetos, permitiéndonos tener un mayor control sobre el proceso 🎛️.
  2. La implementación de este patrón es simple y directa, y su utilidad es casi inmediata 🚀.
  3. Añadir métodos utilitarios como hasNext() y reset() puede mejorar aún más la eficacia y flexibilidad de nuestra implementación del patrón iterador 🧩.

💪 Ejercicios para practicar 💪

  1. Implementa el patrón iterador para recorrer objetos tipo Set y Map en Javascript 🗺️.
  2. Extiende la clase Iterator para que permita aplicar funciones a los elementos de la colección mientras se recorren (por ejemplo, filtrar o mapear elementos) 🔧.
  3. Crea una aplicación que utilice el patrón iterador para recorrer y procesar datos de una API o base de datos 📊.

🔖 Resumen en 3 puntos 🔖

  1. El patrón iterador permite recorrer colecciones de objetos de manera declarativa y con mayor control 🔍.
  2. La implementación básica del patrón iterador en Javascript requiere los métodos first(), next() y current() 📚.
  3. Es recomendable añadir métodos utilitarios como hasNext() y reset() para mejorar la eficacia y flexibilidad de nuestra implementación del patrón iterador 🌟.

¡Gracias por leer! Esperamos que esta guía te haya sido útil y te haya proporcionado una comprensión sólida del patrón iterador en Javascript. Si tienes preguntas, comentarios o sugerencias, no dudes en dejar un comentario abajo ⬇️. ¡Buena suerte con tus proyectos y que sigas aprendiendo! 🌈

Sebastian Gomez

Sebastian Gomez

Creador de contenido principalmente acerca de tecnología.

Leave a Reply

0 Comments

Related Posts

Categorias