JavaScript Sets and Maps have been around for a few years now (since 2015!), but I still get a lot of questions about them. My students wonder if they should be substituting traditional objects and arrays with these new data types. While there are some killer use cases for Sets and Maps, you should really look at them like specialized tools and not Swiss army knives.
When to use Sets
A Set is a collection, like an array, except each value must be unique. They're like what would happen if objects and arrays had a baby. Here's a crash course:
You need to remove duplicates
This is the main way I've actually seen Sets used in the wild. It's a handy one liner:
Checking a quick Set of options
Sometimes you have a handful of options and you want to see if something is included. A lot of people make an array and then use includes
. This is the definition of "just my opinion," but I think Sets read nicer:
At this size, they are identical on performance anyway (though more on that later), so it's only aesthetics. I'm forced to use prettier at work, and .has
being short has helped keep my if-checks stay one line long.
You're doing algorithm challenges
If you're using anything with Set theory in an interview, Sets are obviously the go to. You can see on the Set docs how to implement the basic Set actions. This stuff might come up when doing interviews, so it's worth it to take a look. If you're familiar with SQL, this is basically just another way of thinking about joins.
When to use Maps
Maps are honestly something that I thought would take over the landscape, but then when you get down to it: they're not as much of an upgrade as you might think. They are another way to store key/value data, but they're more purpose-driven than objects, so they have some added benefits. Here's a crash course
You care about insertion order
Technically, objects do kind of maintain insertion order with modern JS. HOWEVER there seem to be some caveats to maintaining key order. If you really need to be sure that your key/value pairs maintain their order for iteration, use a Map. This is the one reason I've used Maps in the past. I'm pretty into writing readable code and Maps can convey meaning simply by existing.
It tells the other developers that we aren't just iterating through all the keys however we want, we care about order. And, if you have a coworker like mine who couldn't be bothered to look up what a Map was and didn't care, I still know that the code is locked in to maintain insertion order and nothing they can do can break it.
You need non-string keys
Objects will always stringify anything used as a key, but Maps don't do that. If you tried to use unique objects as object keys themselves, they would all get stringified into '[object Object]'
and overwrite each other. Luckily with Maps, that's not a problem! Each object would function perfectly well as a unique key. And if you used the same object key with a new value, it would overwrite the original value, as you'd expect. It's not a super common scenario, but it's a good trick to know.
You need a frequent O(1) size lookup
If you're doing an algorithm challenge that needs you to keep track of the size of your key/value store, then the .size
property will really come in handy. There's no need to iterate and count up all the keys, so your algorithm won't have it's time complexity impacted. This is a super specific use case, but it wouldn't surprise me if someone built a challenge just for this quirk.
You have a truly massive dataset
It varies by browser, but if you have over 10 million entries in an object, it may be worth it to to use a Map. The reason being is that some browsers allow about 5 million more entries in Maps than objects. But this is so browser specific, I'm not sure how long that will be the case. Also what are you doing with 15 million items in memory??
And that's about it!
If you thought those seem like pretty specialized situations, you'd be right. I bet you that there are edge cases that I missed (please comment on this post in Reddit if you know of any), but those situations above are the good stuff. Which means that you're safe to keep using regular objects a vast majority of the time. If you really want to use Maps and Sets because you love them from other languages, go for it. Just don't feel like you're missing out if you don't.
JSON and Other gotchas
JSON can't encode Maps and Sets properly yet, so that's something that you may want to consider if you're dealing with APIs. You'll need to convert each Map or Set back into a plain old JS object first. I'm sure this will change in the future.
Also you might hear that some people say that Maps are worth it because they are iterable by default. However, since we're already using ES2015+ syntax to get Maps, then we'll also have the Object.keys, values,
and entries
iterator functions as well. Which, sort of steals that thunder a bit. And to my knowledge, Maps don't have any iteration speed bonus. Which leads me to my last point.
"But aren't Maps and Sets faster?"
…Maybe? On MDN's Maps page it says that they, “Perform better in scenarios involving frequent additions and removals of key-value pairs.” However, I personally haven't seen that to be the case in my tests or research. It is true that the Map.delete
function is faster than the object delete
keyword, but there's a catch. The Map.set
function is slower than the object's internal set method, so whatever bonus you might get from faster deletes would get a huge chunk taken out by slower inserts.
Also, certain browsers implement things differently, which means it's not a consistent boost. In my, albeit limited, testing, I found that objects not Maps were faster (though not by much). But the thing about JS performance is that as browsers and run time environments grow, they can choose to boost certain aspects. So in the future it may be absolutely true that Google optimized the heck out of Maps, so use those. I'm just saying that for now, that seems debatable, and not a reason to switch.
As for Sets, there can be no debate that Set.has
is faster than array.includes
(that's O(N) for arrays vs. O(1) for Sets). Unfortunately, Set.add
seems much slower than arr.push
. I think if you were searching hundreds or thousands of times on a list with a ton of items, then Sets might be worth it there. But I'd recommend actually performance testing before swapping.
All in all, I don't think Maps or Sets have a blanket performance advantage. So far, it seems like environments haven't prioritized performance with these new data types. Plus, they always show these benchmarks with operation counts in the "millions of ops a second", and even then the difference is small. Your objects have like...5 properties. No matter what data shape you pick, you're not going to be hurt by performance.
Final verdict
JS devs LOVE shiny new things, but with the exception of those specialized use cases, there isn't much of a reason to use the new data types. They're new tools to add to your toolbox, not replacements.
Happy coding everyone,
Mike