# Iterables & Iterators

## Iterables and Iterators

Are `conventions` implemented by `Arrays`, `Maps`, `Sets` and `strings`, that make them iterable by a iteration protocol.

These Iterable objects are used by:

* Used by `for _ of _`.
* Used by the `spread operator`.

**How an iterator works**

```javascript
const langs = ['A', 'B', 'C'];

const iterator = langs[Symbol.iterator]();

// Will invoke the next element
iterator.next();  -> { value: 'A', done: false }
iterator.next();  -> { value: 'B', done: false }
iterator.next();  -> { value: 'C', done: false }
iterator.next();  -> { value: undefined, done: true }
```

**Creating an Iterator**

```javascript
function createIterator(...args) {
    let i = 0;
    return {
        next() {
            if (i < args.length) {
                return { value: args[i++], done: false }
            }
            else {
                return { value: undefined, done: true }
            }
        }
    }
}

const iterator = createIterator('A', 'B', 'C');

iterator.next();
iterator.next();
iterator.next();
iterator.next();

// This will not work because iterator is not ITERABLE
for (let val of iterator) {
    ...
}
```

To resolve this...

```javascript
function createIterable() {
    return {
        [Symbol.iterator]() {
            let i = 0;
            return {
                next() {
                    if (i < args.length) {
                        return { value: args[i++], done: false }
                    }
                    else {
                        return { value: undefined, done: true }
                    }
                }
            }
        }
    }
}

const iterable = createIterable('A', 'B', 'C');

// Now this works
for (let val of iterable){
    ...
}
```
