You Can’t Loop Over Objects With for-of in JavaScript

Understand the difference between looping over an object and looping over an array

Moon
Moon
Feb 10, 2020 · 4 min read
Image for post
Image for post
Photo by Etienne Boulanger on Unsplash

A quick question. You can’t loop over {x: 1, y:2} with a for-of loop. Why?

If you don’t know the exact reason, you’ve come to the right place! In this post, I will talk about what is iterable.

Let’s First See What You Can Loop Over

First things first. In JavaScript, there are some values you can loop over with for-of and some values you can’t loop over. Typically, you can use for-of with arrays.

Strings can be looped over as well.

But, these values can’t be mapped over.

Once you execute the for-of that gives you an error, you can see that the error message is weird.

None of the variables names are iterable but what does that mean?

An Iterator Is the One You Actually Need

Since ES6, a new feature has been added, Symbol, which is for a unique value. In the Symbol function, there is an object you can call, Symbol.iterator. This is a function that returns the default iterator for an object.

When an object is created, JavaScript internally creates an object named %IteratorPrototype and assigns it to the newly created object’s iterator object.

When this object is used by a for-of loop, for example, JavaScript checks if it has an iterator object, which inherits from %IteratorPrototype, JavaScript’s internal core prototype for iteration. If it doesn’t exist, you’re given the following error.

Meaning, %IteratorPrototype has to be used by an object when it’s created so that it can be looped over, and the iterator object of an object, such as [1, 2, 3], is called Symbol.iterator — its internal term in the specification is %%iterator, but you can’t use this name in your code.

If Type(O) is not Object, throw a TypeError exception.

Symbol.iterator

Every mappable object has a Symbol.iterator — Array, String, TypedArray, Map, and Set. You can explicitly use the iterator function to loop over it.

When you get the iterator object, it looks like this.

It has the next function that moves the head of the pointer of the index of the object and the Symbol.toStringTag method that defines how it prints out the value when its toString is called.

If you call next, it returns this.

done is the property that shows whether all of the indexes are visited by the iterator, and value is the value of the current index.

If you call next again, the return value will be as follows.

Now you know why the value is “e”.

You can keep calling next and check that the value will be “l”, “l”, and “o”, thus its “hello”. If you call next one more time, the return value will be a little bit different.

The value is now undefined and done is true.

Once the iterator loops over all of the indexes of strings or arrays or anything that has the Symbol.iterator, its head that has been pointing to the indexes is now pointing to the empty space.

Thus, the value would be undefined. And done is changed to true, since the head is pointing to the empty space.

Yet, you can keep calling next, it’ll just give you the same response where the value is undefined and done is true.

Make the Object Iterable

Now, let’s create the object iterable, using Symbol.iterator.

It was the original object. What I’m going to do is to add the [Symbol.iterator] function to make it loopable.

The code looks quite messy, but I’ll explain to you how this works.

next() has the scope for this that refers to within next(). So, this in next() won’t look at the obj.

So, first of all, I used Object.entries() to get every entry in obj.

Then, I made the index property for looping over the entriesi: 0.

If i is equal to or greater than the entries length, which means that the iterator finishes looping over the entries, it starts to return { done: true, value: undefined } from the next iterator call.

Until the condition above is met, the return value will be:

Now, the data will be printed successfully.

Conclusion

The factor for deciding if an object in JavaScript is loopable is whether it has Symbol.iterator inside. Only objects that have the Symbol.iterator can be loopable— Array, typically.

So, objects such as { x: 1, y: 2 } aren’t mappable, but there is a way to make it mappable. You can add a customized next() method to them, which I don’t personally recommend — it’s too much work.

Better Programming

Advice for programmers.

Sign up for The Best of Better Programming

By Better Programming

A weekly newsletter sent every Friday with the best articles we published that week. Code tutorials, advice, career opportunities, and more! Take a look

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Moon

Written by

Moon

Frontend React w/ Typescript developer based in S.Korea. Interested in UX/Testing/FE. Currently working at Watcha. mgyang95@gmail.com

Better Programming

Advice for programmers.

Moon

Written by

Moon

Frontend React w/ Typescript developer based in S.Korea. Interested in UX/Testing/FE. Currently working at Watcha. mgyang95@gmail.com

Better Programming

Advice for programmers.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store