# JavaScript iterators tutorial with examples | introduction to the iterable object

What’s an iterable object anyway? What does it meant to "implement the iterator
protocol", and how to build a custom iterator.

Iterators in JavaScript are a relatively new new thing, they’ve been around for
few years. Let’s just jump into it with examples.

## What is an iterator?

Iterator is not an array, but it can behave a bit like an array, in the sense
that you can iterate it over with a loop construct.

[MDN article](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators)
defines an iterator as such:

> Specifically, an iterator is **any object which implements the Iterator
> protocol** by having a `next()` method that returns an object with two
> properties:

value
  The next value in the iteration sequence.
  done

This is true if the last value in the sequence has already been consumed. If
    value is present alongside done, it’s the iterator's return value.

So, what exactly is the iterator protocol then? **That’s basically what this
post tries to explore**.

## Dissecting the iterator

The [`for...of` loop](/the-new-es6-for-of-loop-with-javascript) construct can
work with iterables. If `for...of` would be a person, and you’d ask it, "What is
an array?" it would be just like, "I don’t know 🤷‍♀️". See,`for...of` doesn’t
exactly work in the array department of the JavaScript corporation. But, if you
try to loop an array with it, it behaves like you’d assume it would:

```js
const things = ['egg', 'thermometer', 'matryoshka', 'banana']

for (const thing of things) {
  console.log(thing)
  // egg thermometer matryoshka banana
}
```

So what’s up? It’s the iterator working behind the scenes. If you dir the the
`things` array with `console.dir(things)`, and look into its `__proto__`
property:

![Array method’s prototype](/images/iterator-in-array-prototype.png)

See that `Symbol.iterator` there? It can be accessed like so:

```js
const iterator = things[Symbol.iterator]()
console.log(iterator)
```

That above log tells us that the iterator has a method called `next()`, **which
is the heart of this whole thing**. The `next()` method can be called manually
and it’ll get the next item in the iterable (which in this case is the first
item, because we’re calling it the first time):

```js
console.log(iterator.next())
// Object
//   done: false
//   value: "egg"
```

It has those two properties mentioned earlier: `done`, and `value`.

If the `next()` is called more times than we have items in our test array, the
`done` would eventually turn into `true`, signaling that we’re done here,
nothing to iterate anymore:

```js {5}
console.dir(iterator.next().done) // false
console.dir(iterator.next().done) // false
console.dir(iterator.next().done) // false
console.dir(iterator.next().done) // false
console.dir(iterator.next().done) // true
```

So the `for...of` loop works by calling `next()`, then grabbing data from
`next().value`, and checking if it should keep going from `next().done`. **That
is the iterator basically**.

## Make your own iterable object

In this example I’m not doing anything special for the shape that I’m working
with (bad imagination), but there’s a lot of changes to manipulate the data in
many different ways. Constructing your own iterators gives you a lot of freedom.

```js
const things = {
  things: {
    egg: 'Chicken capsule',
    thermometer: 'Air spiciness gauge',
    matryoshka: 'Grandma multiplier',
    banana: 'Longular fruit',
  },
  [Symbol.iterator]: function () {
    let index = 0
    const keys = Object.keys(this.things)

    return {
      next: () => {
        const hasMore = index < keys.length

        if (hasMore) return { done: false, value: this.things[keys[index++]] }

        return { done: true }
      },
    }
  },
}

for (let thing of things) {
  console.log(thing)
}
```

See a simple demo in CodeSandbox:

[![Edit custom-iterator](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/custom-iterator-h51je?fontsize=14&hidenavigation=1&theme=dark)

## Turn iterable object to an array

For example, a JavaScript `Set` is iterable, but it’s _not_ an Array, it’s an
Object:

```js
const mySet = new Set(['foo', 'bar'])
console.log(typeof mySet) // object
// ❌ Won’t work obvs
const prefixedValues = mySet.map(x => '_' + x)
```

Maybe you want to use array methods on your iterable, like `map` or `filter`,
you can very easily turn the iterable object into an Array by spreading it. The
same methods are introduced with objects in
[this JavaScript array methods guide](/javascript-manipulating-objects-with-object-keys):

```js
const prefixedValues = [...mySet].map(x => '_' + x) // ✅
```

## Test if something is iterable

Here’s a simple helper function to test if something is iterable:

```js
const isIterable = input => Boolean(input?.__proto__[Symbol.iterator])
```

Feed it data types:

```js
console.log(
  isIterable({ foo: 'foo' }),
  isIterable(['foo', 'bar']),
  isIterable(new Map()),
  isIterable(new WeakMap())
)
```

Iterability of different JS data types

Data type
      JS syntax
      Is iterable

Booleans

`true|false`

[Interactive example](/iterators)

Undefined values

`undefined`

[Interactive example](/iterators)

Null values

`null`

[Interactive example](/iterators)

Objects

``

[Interactive example](/iterators)

Strings

`'foo'`

[Interactive example](/iterators)

Empty strings

`''`

[Interactive example](/iterators)

Maps

`new Map()`

[Interactive example](/iterators)

Weak maps

`new WeakMap()`

[Interactive example](/iterators)

Sets

`new Set()`

[Interactive example](/iterators)

Weak Sets

`new WeakSet()`

[Interactive example](/iterators)

Generators

``

[Interactive example](/iterators)
