DEV Community

Alireza Razinejad
Alireza Razinejad

Posted on • Updated on

Create our own iterable in JavaScript

In this article we are going to see how we can create our iterator and iterable objects. 😎

Usually when we are creating an Array object in JavaScript, we are creating an iterable object that have iterator Symbol (symbol is just data type like string, boolean, etc, for more information check out here), and this symbol object will let us go throw objects inside the array using for of loop. 🤗

Okay, first let's see our simple way of creating iterable objects 🧐

const ourArray = [1, 2, 3, 4, 5];

for (const el of ourArray) {
    console.log(el);
}

// out put will be 1 2 3 4 5
Enter fullscreen mode Exit fullscreen mode

Now let's create our own iterator and iterable 🤓

const ourOwnIterable = {
    [Symbol.iterator]() {
        return {
            next: () => { 
                return {
                    value: 'This works',
                    done: false
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

That's it, now we have our own iterable, just because Symbol.iterator will return the object that have next() function, and that next() function will return the object that contains value and done, and that's obvious what do they do, let's say we use for-of loop to go throw our iteratable object, when ever javascript see the done is true, it will stop reading the objects and will close the loop.

But if we run this code right now, we will stuck into an infinite loop that will never end 🤢

To fix this and make our iterable object works fine, we need values, and the way to see if, we are done reading values ? first let's add some value to ourOwnIterable object 😏

const ourOwnIterable = {
    value: [1, 2, 3, 4, 5],
    index: 0,
    [Symbol.iterator]() {
        return {
            /**
             * Our iterator will start here
             * @returns {{value: *, done: boolean}}
             */
            next: () => {
                return {
                    value: this.value[this.index],
                    done: false
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Now we have our values ready to be access able, using for-of loop, but still we need to implement some logic to set done, to true when ever our iterator reach the last value

const ourOwnIterable = {
    value: [1, 2, 3, 4, 5],
    index: 0,
    [Symbol.iterator]() {
        return {
            /**
             * Our iterator will start here
             * @returns {{value: *, done: boolean}}
             */
            next: () => {
                if(this.value.length === this.index) {
                    return {
                        value: null,
                        done: true
                    }
                }

                this.index++;

                return {
                    value: this.value[this.index - 1],
                    done: false
                }
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

That's it ! Now, we have our own iterable object that we can iterate throw values 🥱😁

And now we can use for-of loop on ourOwnIterable object like so

for (const el of ourOwnIterable) {
    console.log(el);
}
Enter fullscreen mode Exit fullscreen mode

Thank you for your time 🤝
Hope you enjoy it ❤

Latest comments (6)

Collapse
 
0x04 profile image
Oliver Kühn

Nice! But one thing I have to mention: If you use a fat arrow function for next there is no need for const that = this - always found this "hack" some kind of inelegant 😅

Collapse
 
ussdlover profile image
Alireza Razinejad

😁
Should I edit 🙄
Yes 🙃

Collapse
 
patarapolw profile image
Pacharapol Withayasakpunt • Edited

Can I make it as easy as Python's def __iter__(self) and yield?

I know there is yield in JavaScript somewhere, but I never used it.

Collapse
 
ussdlover profile image
Alireza Razinejad

Not that much easy.
But we can do something like this

/**
 * @param val
 * @returns {Generator<*, void, *>}
 */
function* ourOwnInterable(val) {
    while (val < 3) {
        yield val;
        val++;
    }
}

/**
 * @type {Generator<*, void, *>}
 */
const iterator = ourOwnInterable(0);

for (const el of iterator) {
    console.log(el);
}
Enter fullscreen mode Exit fullscreen mode
Collapse
 
reykcs profile image
Reyk • Edited

Wow im programming with javascript since like 4 years and i have never used nor seen those generator functions. So definitely thank you for this hint!

Always thought the usage of the asterisks in declarations is limited to pointers in c and c++ 😅

Collapse
 
badreddine11 profile image
ABDELLAOUI

Hi