Originally published on stevebrownlee.com
Imagine that you have an object in JavaScript that maintains a list of items, and you want the object itself to be iterable, but the object also has other important properties - such as metadata about the list of items.
Here's a fun and completely original example.
const se7enDwarves = {
employment: "Miners",
output: "Diamonds",
members: new Map()
}
se7enDwarves.members.set(1, "Sleepy")
se7enDwarves.members.set(2, "Grumpy")
se7enDwarves.members.set(3, "Happy")
se7enDwarves.members.set(4, "Bashful")
se7enDwarves.members.set(5, "Sneezy")
se7enDwarves.members.set(6, "Doc")
se7enDwarves.members.set(7, "Dopey")
I now have an object that represents the seven dwarves. It holds their names in an iterable collection, but also other relevent data about them. I would love to be able to iterate over the object itself, instead of having to type in that horrible, troublesome property namespace of members
.
I want to see the names of all the dwarves, so I use the spread syntax to iterate the object and place the items in an array.
[...se7enDwarves]
VM2417:1 Uncaught TypeError: se7enDwarves is not iterable
at <anonymous>:1:5
JavaScript, in all kinds of holy righteousness, tells me that I can't iterate an object like that.
Hmph.
Luckily, JavaScript allows developers to perform what is called metaprogramming. It's a feature of the language that allows us to modify some of the default behaviors of the underlying data structures available to us. I can make an object iterable.
se7enDwarves[Symbol.iterator] = function* () {
const states = se7enDwarves.members.values()
let state = null
do {
state = states.next().value
if (typeof state !== "undefined") yield state
} while (typeof state !== "undefined")
}
High level overview... I made the object iterable. Thought I'd point that out in case it wasn't obvious from that "self-documenting code".
[...se7enDwarves]
(7) ["Sleepy", "Grumpy", "Happy", "Bashful", "Sneezy", "Doc", "Dopey"]
Try it Out on jsfiddle
I create a JSFiddle for you to play around with this code yourself.
Top comments (2)
Great article Steve, especially that you found a real world use case of making a custom iterable object. I had similar fun while writing How I learned to Stop Looping and Love the Iterator, though I wish I could add a section on generators.
One suggestion for you to improve the iterator of your
se7enDwarves
, is that you can redirect iteration to another iterable using yield *:Thanks, Kushan. I did realize that the iterator could be simplified about a month after I wrote the original article, but never updated it, so thanks for posting what that looks like. Great stuff.