--- title: Protocolos de Iteración slug: Web/JavaScript/Reference/Iteration_protocols tags: - ECMAScript6 - Experimental - Intermedio - Iterable - Iterador - JavaScript translation_of: Web/JavaScript/Reference/Iteration_protocols original_slug: Web/JavaScript/Referencia/Iteration_protocols ---
El protocolo iterable le permite a los objetos en JavaScript definir o personalizar su comportamiento de iteración, como por ejemplo qué valores son iterados dentro de una sentencia {{jsxref("Statements/for...of", "for..of")}}. Algunos objetos nativos, como {{jsxref("Array")}} o {{jsxref("Map")}}, tienen un comportamiento de iteración por defecto, mientras otros objetos (como por ejemplo {{jsxref("Object")}}) no.
Para ser iterable, un objeto debe implementar el método @@iterator, lo cual significa que el objeto (o uno de los objetos dentro de su cadena de prototipos) debe tener una propiedad con un identificador {{jsxref("Symbol")}}.iterator:
| Propiedad | Valor | 
|---|---|
[Symbol.iterator] | 
   Una función sin argumentos que retorna un objeto, de acuerdo al protocolo iterador. | 
Siempre que un objeto necesite ser iterado (como al comienzo de un for..of loop), su método @@iterator es llamado sin argumentos, y el iterador retornado es usado para obtener los valores a ser iterados.
El protocolo iterador define una forma estándar que permite producir una secuencia de valores (sean estos finitos o infinitos).
Un objeto es un iterador cuando este implementa un método next() con la siguiente semántica:
| Propiedad | Valor | 
|---|---|
next | 
   
     Una función sin argumentos que retorna un objeto con dos propiedades: 
  | 
  
Algunos iteradores son a su vez iterables:
var someArray = [1, 5, 7]; var someArrayEntries = someArray.entries(); someArrayEntries.toString(); // "[object Array Iterator]" someArrayEntries === someArrayEntries[Symbol.iterator](); // true
Un {{jsxref("String")}} es un ejemplo de un objeto iterable nativo:
var someString = "hi"; typeof someString[Symbol.iterator]; // "function"
Para objetos String su iterador por defecto retorna cada uno de sus caracteres, uno a la vez:
var iterator = someString[Symbol.iterator]();
iterator + "";                               // "[object String Iterator]"
iterator.next();                             // { value: "h", done: false }
iterator.next();                             // { value: "i", done: false }
iterator.next();                             // { value: undefined, done: true }
En algunas estructuras nativas del lenguaje como en el caso del operador de propagación spread operator, el mismo protocolo de iteración está presente en su parte interna:
[...someString] // ["h", "i"]
Podemos redefinir el comportamiento de iteración creando nuestro propio  @@iterator:
// es necesario el uso de un objeto creado a partir de la función constructora String,
// ya que al usar un string primitivo el auto-boxing generaría una referencia temporal
// a un iterador que luego es descartado en el unbox
var someString = new String("hi");
someString[Symbol.iterator] = function() {
  return { // este es el objeto iterador que retorna un único elemento, la cadena string "bye"
    next: function() {
      if (this._first) {
        this._first = false;
        return { value: "bye", done: false };
      } else {
        return { done: true };
      }
    },
    _first: true
  };
};
Nótese que al redefinir un @@iterator se puede afectar el comportamiento  de construcciones nativas que usan el protocolo de iteración:
[...someString]; // ["bye"] someString + ""; // "hi"
{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("TypedArray")}}, {{jsxref("Map")}} y {{jsxref("Set")}} son objetos iterables nativos, ya que en su objeto prototipo existe un método @@iterator.
Podemos crear nuestros propios iterables de la siguiente manera:
var myIterable = {};
myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};
[...myIterable]; // [1, 2, 3]
Existen varios APIs que aceptan iterables, como en el caso de: {{jsxref("Map", "Map([iterable])")}}, {{jsxref("WeakMap", "WeakMap([iterable])")}}, {{jsxref("Set", "Set([iterable])")}} y {{jsxref("WeakSet", "WeakSet([iterable])")}}:
var myObj = {};
new Map([[1,"a"],[2,"b"],[3,"c"]]).get(2);               // "b"
new WeakMap([[{},"a"],[myObj,"b"],[{},"c"]]).get(myObj); // "b"
new Set([1, 2, 3]).has(3);                               // true
new Set("123").has("2");                                 // true
new WeakSet(function*() {
    yield {};
    yield myObj;
    yield {};
}()).has(myObj);                                         // true
De igual manera {{jsxref("Promise.all", "Promise.all(iterable)")}}, {{jsxref("Promise.race", "Promise.race(iterable)")}}, y {{jsxref("Array.from", "Array.from()")}}.
Algunas declaraciones y expresiones esperan iterables, por ejemplo el bucle for-of, el operador de propagación spread operator,  la expresión Yield*, y la asignación desestructurada destructuring assignment.
for(let value of ["a", "b", "c"]){
    console.log(value);
}
// "a"
// "b"
// "c"
[..."abc"]; // ["a", "b", "c"]
function* gen(){
  yield* ["a", "b", "c"];
}
gen().next(); // { value:"a", done:false }
[a, b, c] = new Set(["a", "b", "c"]);
a // "a"
Un método @@iterator iterable que no retorne un objeto iterador no está correctamente definido, por lo tanto al ejecutarlo de esta manera podría resultar en excepciones en tiempo de ejecución y otros errores:
var nonWellFormedIterable = {}
nonWellFormedIterable[Symbol.iterator] = () => 1
[...nonWellFormedIterable] // TypeError: [] is not a function
function makeIterator(array){
    var nextIndex = 0;
    return {
       next: function(){
           return nextIndex < array.length ?
               {value: array[nextIndex++], done: false} :
               {done: true};
       }
    };
}
var it = makeIterator(['yo', 'ya']);
console.log(it.next().value); // 'yo'
console.log(it.next().value); // 'ya'
console.log(it.next().done);  // true
function idMaker(){
    var index = 0;
    return {
       next: function(){
           return {value: index++, done: false};
       }
    };
}
var it = idMaker();
console.log(it.next().value); // '0'
console.log(it.next().value); // '1'
console.log(it.next().value); // '2'
// ...
function* makeSimpleGenerator(array){
    var nextIndex = 0;
    while(nextIndex < array.length){
        yield array[nextIndex++];
    }
}
var gen = makeSimpleGenerator(['yo', 'ya']);
console.log(gen.next().value); // 'yo'
console.log(gen.next().value); // 'ya'
console.log(gen.next().done);  // true
function* idMaker(){
    var index = 0;
    while(true)
        yield index++;
}
var gen = idMaker();
console.log(gen.next().value); // '0'
console.log(gen.next().value); // '1'
console.log(gen.next().value); // '2'
// ...
Un objeto iterador es tanto un iterador como un iterable:
var aGeneratorObject = function*(){
    yield 1;
    yield 2;
    yield 3;
}();
typeof aGeneratorObject.next;
// "function", ya que tiene un método next, por lo tanto es un iterador
typeof aGeneratorObject[Symbol.iterator];
// "function", ya que tiene un método @@iterator, por lo tanto es un iterable
aGeneratorObject[Symbol.iterator]() === aGeneratorObject;
// true, ya que su método @@iterator retorna a sí mismo (un iterador), por lo tanto es un iterable bien formado
[...aGeneratorObject];
// [1, 2, 3]
| Especificación | Estado | Comentario | 
|---|---|---|
| {{SpecName('ES6', '#sec-iteration', 'Iteration')}} | {{Spec2('ES6')}} | Definición inicial. | 
Para información adicional acerca de generadores generators en ES6, puede visitar la página específica sobre este tema.