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
Update
Kushan Joshi provided an update to this code on dev.to that simply defers the generator to another generator. A nice solution.
se7enDwarves[Symbol.iterator] = function* () {
yield * se7enDwarves.members.values();
}
[...se7enDwarves]
(7) ["Sleepy", "Grumpy", "Happy", "Bashful", "Sneezy", "Doc", "Dopey"]