Iteration protocols
===================

Algumas adições do ECMAScript 2015 não são novos *built-ins* ou uma nova sintaxe, mas protocolos. Estes protocolos podem ser implementados por qualquer objeto desde que respeitando algumas convenções.Existem dois protocolos: O *protocolo iterável* (iterable protocol) e o *protocolo iterador* (iterator protocol).O protocolo iterável (iterable protocol)
----------------------------------------

O protocolo **iterável** permite que objetos JavaScript definam ou personalizem seu comportamento de iteração, como valores em um loop do construtor `for..of`. Alguns tipos *built-in* são *built-in iterables* com um comportamento de iteração padrão, tal como `Array` ou `Map`, enquanto outros tipos (como `Object`) não são assim.

Para ser **iterável**, um objeto deve implementar o método **@@iterator**, o que significa que o objeto (ou um dos objetos acima de sua cadeia de protótipos) deve ter uma propriedade com uma chave **@@iterator** que está disponível via constante ``Symbol.iterator``:

| Property | Value |
| --- | --- |
| `[Symbol.iterator]` | Uma função de zero argumentos que retorna um objeto, em conformidade com o protocolo iterador. |

Sempre que um objeto precisa ser iterado (como no início de um loop `for..of`), o método `@@iterator` é chamado sem argumentos e o retorno do **iterador** é usado para obter os valores a serem iterados.

O protocolo iterador (iterator protocol)
----------------------------------------

O protocolo **iterador** define uma maneira padrão de produzir uma sequência de valores (finito ou infinito).

Um objeto é um iterador quando implementa um método **`next()`** com a semântica adiante:

| Propriedade | Valor |
| --- | --- |
| `next` | Uma função sem argumentos que retorna um objeto com duas propriedades:* `done` (boolean)
    + Tem o valor `true` se o iterador ultrapassar o final
     da sequência iterada. Nesse caso
     `value` opcionalmente especifica o valor de retorno
     do iterador.
    + Tem o valor `false` se o iterador foi capaz de
     produzir o próximo valor na sequência. Isso é equivalente a não
     especificar a propriedade `done`.
* `value` - qualquer valor JavaScript retornado pelo
 iterador. Pode ser omitido quando `done` é
 `true`.

 O método `next` sempre retorna um objeto com propriedades
 apropriadas, incluindo `done` e `value`. Se um
 valor não-objeto é retornado (tal como `false` ou
 `undefined`), será lançado um
 `TypeError` ("iterator.next() retorna o valor de
 um não-objeto").
  |

**Nota:** Não é possível saber de forma reflexiva se um determinado objeto implementa o protocolo do iterador, no entanto, é fácil criar um objeto que satisfaça tanto o iterador quanto os protocolos iteráveis (como mostrado no exemplo abaixo). Fazer isso permite que um iterador seja consumido pelas várias sintaxes que iteráveis esperam. Assim, raramente é desejável implementar o protocolo do iterador sem também implementar iteráveis.


```js
var myIterator = {
  next: function () {
    // ...
  },
  [Symbol.iterator]: function () {
    return this;
  },
};
```


Exemplos de uso do protocolo de iteração
----------------------------------------

Uma `String` é um exemplo de um objeto iterable built-in:


```js
var someString = "hi";
typeof someString[Symbol.iterator]; // "function"
```


O iterador padrão de uma string retorna as posições dos caracteres de uma string um por um:


```js
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 }
```


Alguns construtores built-in, como *spread syntax*, usam o mesmo protocolo de iteração interiormente:


```js
[...someString]; // ["h", "i"]
```


Podemos redefinir o comportamento de iteração fornecendo nosso próprio `@@iterator`:
```

var someString = new String('hi');           // need to construct a String object explicitly to avoid auto-boxing

someString[Symbol.iterator] = function() {
  return { // this is the iterator object, returning a single element, the string "bye"
    next: function() {
      if (this._first) {
        this._first = false;
        return { value: 'bye', done: false };
      } else {
        return { done: true };
      }
    },
    _first: true
  };
};
```


Observe como redefinir `@@iterator` afeta o comportamento built-in que faz uso do protocolo de iteração:


```js
[...someString]; // ["bye"]
someString + ""; // "hi"
```

Exemplos de Iteráveis
---------------------

### Iteráveis Built-in

`String`, `Array`, `TypedArray` (en-US), `Map` and `Set` são todos iteráveis internos, porque cada um dos seus objetos protótipos implementa um método `@@iterator`.

### Iteráveis definidos pelo usuário

Nós podemos fazer nossos próprios iterables assim:
```

var myIterable = {};
myIterable[Symbol.iterator] = function* () {
    yield 1;
    yield 2;
    yield 3;
};
[...myIterable]; // [1, 2, 3]
```

### Built-in APIs que aceitam iteráveis

Existem muitas APIs que aceitam iteráveis, por exemplo: `Map([iterable])`, `WeakMap([iterable])`, `Set([iterable])` e `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
```


Veja também `Promise.all(iterable)`, `Promise.race(iterable)` e `Array.from()`.

### Sintaxe que espera iteráveis

Some statements and expressions expect iterables, for example the `for-of` loops, spread operator (en-US), `yield*`, and 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"
```

### Iteráveis não bem formados

If an iterable's `@@iterator` method doesn't return an iterator object, then it's a non-well-formed iterable. Using it as such is likely to result in runtime exceptions or buggy behavior:
```

var nonWellFormedIterable = {}
nonWellFormedIterable[Symbol.iterator] = () => 1
[...nonWellFormedIterable] // TypeError: [] is not a function
```

Iterator examples
-----------------

### Simple iterator
```

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
```

### Infinite iterator
```

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'
// ...
```

### Com um gerador
```

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'
// ...
```

### Com uma classe ES2015
```

class SimpleClass {
  constructor(data) {
    this.index = 0;
    this.data = data;
  }

  [Symbol.iterator]() {
    return {
      next: () => {
        if (this.index < this.data.length) {
          return {value: this.data[this.index++], done: false};
        } else {
          this.index = 0; //If we would like to iterate over this again without forcing manual update of the index
          return {done: true};
        }
      }
    };
  }
}

const simple = new SimpleClass([1,2,3,4,5]);

for (const val of simple) {
  console.log(val);  //'0' '1' '2' '3' '4' '5'
}
```

Um objeto gerador um iterador ou iterável?
------------------------------------------

Um objeto gerador é tanto iterador quanto iterável:
```

var aGeneratorObject = function* () {
    yield 1;
    yield 2;
    yield 3;
}();
typeof aGeneratorObject.next;
// "function", because it has a next method, so it's an iterator
typeof aGeneratorObject[Symbol.iterator];
// "function", because it has an @@iterator method, so it's an iterable
aGeneratorObject[Symbol.iterator]() === aGeneratorObject;
// true, because its @@iterator method returns itself (an iterator), so it's an well-formed iterable
[...aGeneratorObject];
// [1, 2, 3]
```

Especificações
--------------

| Specification |
| --- |
| ECMAScript Language Specification # sec-iteration |

Veja também
-----------

* Para mais informações sobre *generators* ES2015, consulte a documentação de function\*.