689

November 6th, 2023 × #javascript#webdev#podcast

You Should Be Using JavaScript Maps & Sets

Wes and Scott discuss JavaScript maps and sets - how they differ from arrays and objects, unique use cases, and when to reach for maps/sets over arrays/objects.

or
Topic 0 00:17

Maps and sets - spicy buffalo objects

Scott Tolinski

Welcome to Syntax. On this Monday hasty treat, we're gonna be talking about you should be using maps and sets within JavaScript.

Scott Tolinski

What they are, why they come in handy, some of the reasons why they differ from arrays and objects, and just in general, What is up with maps and sets? My name is Scott Tolitsky. I'm a developer from Denver, and with me as always is Wes Bos. What's up, my man? Hey. I

Wes Bos

Thought we should do a show on maps and sets and how you should use them. They've been around for probably 8 years or so. Stuff. It still feels like a relatively new part to JavaScript. But in not all cases, but in many cases, Reaching for a map and a set or a map or a set versus an object or an array can sometimes be a pleasant experience, can sometimes be how they work as well as, like like, you actual use cases that you might wanna use them in your applications. Yeah. They're neat, And I don't think they get enough love.

Topic 1 01:08

Maps can have any type as a key

Scott Tolinski

And if you're using any new API like you might be using with maps and sets, you should probably have some error and exception handling tracking service To make sure that if you're running bugs with any of these new APIs, you're trying to use them like you would use an object or an array, and you don't know your way around them, well, you might be hitting some bugs here. So check it out. Wanna check out century.io because this podcast is brought to you by Century.

Scott Tolinski

So let's get going here. We're gonna start with maps, which are kind of like they're kind of like I I don't know if you wanna say they're they're supercharged objects or something like that because they're analogous to objects in many ways.

Scott Tolinski

But do you wanna talk spicy buffalo object? Spicy buffalo object. Perfect. Yeah.

Scott Tolinski

Yeah. Do you wanna talk about what makes them a spicy buffalo object?

Topic 2 02:21

Sets automatically deduplicate values

Wes Bos

Yeah. So, you can think of maps as sort of a key value store, very similar to an object where you have property value.

Wes Bos

And the benefit of a map, along with the API, we'll talk about in a second. But probably the biggest benefit to me is that the key of a map can be any type. So right now with an object, the key of an object can be 3 things. Do you know what those 3 things are Or maybe 2 things.

Scott Tolinski

To 2 I don't I I mean, a string.

Scott Tolinski

Yep.

Scott Tolinski

A

Wes Bos

symbol? I don't know. Symbl? Good. That's the second one. I guess Oh, I know it. Yeah. You got it. You could guess. Yeah. Okay. I don't know if the third one is is technically correct or not, but You can set a number as a as a property on an object. However, the that will be translated into Does it get translated into a string? To a string? Yeah. See, that's what I like. Visually, I see it as a string when I think the key. When you when you pull it out of an object, it comes out as a string.

Scott Tolinski

Okay. But let's, let me let me try it right now. Yeah. We got a console. We got a, what do they call that? Is it just a console? When you type you can just type it in JavaScript. Let's go. Yeah, there's no differentiation

Wes Bos

between a number and a string on an object, So they both come out as strings if you were to run object dot keys on it. So that's that's your limitation to an object right now is that The keys must be some sort of unique string or a symbol, which is a symbol is a way to make a unique ID out of something that might be a duplicate. So, like, if I had a key of Wes And then I later I had a Key of Wes as well. Those things would overlap each other. You wrap it in a symbol, and all of a sudden you have this infinitely unique thing that will never be overwritten. And sometimes that's helpful for creating keys in maps or objects or anything like that. But that's not what we're talking about today. We're talking about how a key of a map can be literally anything, and it Can be an another object. It can be obviously a string, can be a number, can be an array of actual items. So an example that I use in my beginner JavaScript course is how many times has this this button been clicked? Right? There's this idea in JavaScript that sometimes you wanna keep a dictionary or a running tally of data about something, but you don't want to stick that data on the element. So a button, if you want to track how many times a button has been clicked You with an object, you would either have to stick the number of clicks on the object itself or you create a totally separate object And you somehow create a unique ID for that element itself, and then you reference it. Like, maybe the maybe you have an ID 123 on that div.

Topic 3 04:52

Looping over maps and sets

Wes Bos

With a map, you can literally just query selector, select the dom element itself, and stick that dom element as the key. So So you see what I mean by that? The key of a map can be anything. And then if you ever want to reference how many times an element has been clicked, you simply just say, like my click count get and you pass it the dom element and it will return the actual value, right? You just give it an object.

Wes Bos

You can give it any value that you want. So again, if you have an array of data about a person, you could use that entire array as the key for that map. So counting instances is really popular.

Wes Bos

Grouping by. There's a new method on it called Groupby.

Wes Bos

This is a very common thing to do is If you have an array of items and you wanna group them by a specific person, like, we have 20 utterances in this show, and I wanna group them by the ones that I've said in the ones that Scott have said, I don't have to get the ID of Scott, because what happens if there's a guest named Scott? You know, now everybody has to have a unique identifier.

Topic 4 06:42

Use cases - metadata, dictionaries, lookups

Wes Bos

I can simply just pass Scott the object because you're a you're a person in in the code and I can use that as a reference for it. So it's really handy for these, like, metadata, dictionary,

Scott Tolinski

lookups, things like that. And and so to be be clear, would be way more performant than even doing, like, an object and then running it through a loop to manually group by because it is

Wes Bos

Knows where everything is. Right? Yeah. I think so. So the documentation for maps and sets say they are more performant than their Equivalents.

Wes Bos

That comes with a bit of a more a bit more limitations.

Wes Bos

But in many cases, quickly referencing a value can be much faster. Interesting.

Wes Bos

Again, with all things, it might not matter.

Scott Tolinski

Specific use case. So what you're saying is I should always use maps for everything now.

Wes Bos

No. I'm saying maybe maybe see is like, is this a use case where I could Use a specific map.

Wes Bos

The API of a map is pretty simple. You say new map and you can pass it You can just create a blank map or you can pass it a what I call entries.

Wes Bos

So, you know, when you call object entries on something you get an array in each item. The key value is a sub array.

Wes Bos

1st item is the key. 2nd item is the value. You can create a map from those entries values. And then when you have a map, the API is just get, set, has, and clear.

Wes Bos

And even if you aren't using maps directly, if you ever need to make your own data structure that has getters, setters, deletes, and clears. This is a very good primitive to build on top of because it has all of these things and it is native to the platform rather than having to make your own class and implement getter setters and all that good stuff from the beginning.

Wes Bos

Looping over items in a map is pretty straightforward.

Wes Bos

So you have a dot For each method on a map, you do not have map on a map.

Wes Bos

You do not have reduce filter, all of that stuff. I got that's more for sets, but you don't have any of those for sets either. You just have a for each or a for of loop to iterate over the items.

Wes Bos

And then if you wanna see how many items are in a map,

Scott Tolinski

you can use the dot size property. So I have some questions for you because

Wes Bos

these are maps still feel mysterious to me. So can you change the size of a map after it's created? Stuff. Yes, you can. And sorry. I I just said that there's a dot size property on a map. That's not true. There is a dot size property on a set.

Wes Bos

Okay. Because a set is a group of items.

Wes Bos

So, yeah, you can change the size any given time, you simply just add or remove items. Dot set method. Yeah. A dot set method. Not a set itself.

Wes Bos

Jeff. Sometimes it's hard to search for what you want.

Topic 5 09:55

API for maps and sets

Scott Tolinski

We gonna be, you can't map the map. You got gotta add the set to the map, but not the set to the set. Jeff. Yeah. Yeah.

Scott Tolinski

Mhmm. Yeah. The language is tough here. But okay.

Scott Tolinski

Another question. So unlike an object, are you not able to access properties directly. You have to use a dot get to access the value of a property, right? Correct. Yes. If you you can't just say, like,

Wes Bos

show.title.

Wes Bos

You would have to say You have to use .get. Exactly.

Scott Tolinski

Okay. And lastly, because of that, I would assume that means the Spread operator is not something that you can use with these. Right? Because if you spread out a map, what are you getting? The internals of the map and not

Wes Bos

The data itself. Yes. A spread operators are only for objects and arrays.

Wes Bos

So when you get into I want to do this object dish thing or array ish thing with a map, Often what you'll find yourself doing is you can convert it back to an object or array, do your work and then throw it back in.

Wes Bos

Stuff. And a lot of times that does make sense. And then some cases you say, oh, you know what? This is more something that I should be using an object for.

Wes Bos

Word. I think the I think the biggest benefit here is a in deciding if you want to use the map is a, do I want the clean API and not the whole prototype chain look up has own property business that that works with objects. You know, like, the thing with objects is if that object has been extended from another object and you try to access a property, If it's not on that object, it will look up the prototype chain for another one. And sometimes that cannot be what you want. So you have to use hasOwn property. So, like, if you're like, you know, I just want a nice clean data store with get set has delete and clear methods, And I wanna be able to use any type, including objects,

Scott Tolinski

as the keys, then a map is where you wanna go. Interesting. Yeah. That's a good Good way to put it. Right? You're using it potentially as a data store.

Topic 6 12:08

Using maps as a cache

Scott Tolinski

It could be like even I don't know if you would implement, like, an in memory cache with a dot map, but, I mean, that's that's the type of thing I think about when I think about needing a a data store. Let's talk about where we used a a map as a cache. So on the syntax

Wes Bos

website for our Open Graph images.

Wes Bos

It's the same code as my personal westboss.comopengraphimages.

Wes Bos

We have a serverless function that will take a screenshot of this HTML page and turn that into a PNG, right? That's how we generate our Open Graph images. We design them with HTML and CSS, take a screenshot, and then it's a PNG at the other end. We just convert those to base 64 and store them in memory because they regenerate whenever we need them.

Wes Bos

And what are we using to store the as a cache, we're using a map. So on the serverless function, we have a new map.

Wes Bos

And then I think the keys of the map are what are what are the keys of the map? Maybe the show number? It could it could be anything. You could literally put the show as a key in the map. And then when we somebody requests a Open Graph image, We check if that map already has the image. If so, we return the cached version, and if not, we regenerate it and throw it in the map for next time that it's Cached.

Scott Tolinski

Word. That that's a very good example. It's it's using it as a cache. Okay. Well, let's get into sets now. Okay? And we're talking about the array like things that are, you know, analogous to maps, but array like.

Topic 7 13:45

Sets vs arrays

Scott Tolinski

What makes a set an array with buffalo sauce on it?

Wes Bos

Sets are actually honey garlic arrays.

Wes Bos

Honey garlic arrays. Wonderful. I actually do like I like the honey garlic. Yeah. Yeah. I'm a big, big honey garlic fan too. Stuff. I'll show up for that. Yeah.

Wes Bos

The unique thing about a set is that the items are automatically uniqueified. So if you add the same item to a set twice and this is referenced by reference, meaning that if you add the same object, the object itself, not like the 2 objects with the same values, but the same object twice, Then it will only be added once, which is sometimes nice if you're trying to loop over a bunch of data. You don't have to check if it's in there already before you go ahead. You don't have to deduplicate any of the data that you have, as well as it's pretty common for people to take an array, throw it into a set, And then put it back into an array just to get the benefit of that's a pretty quick way to an easy way to make a an array unique. Yeah. Stuff. So you don't have to dedupe

Scott Tolinski

a set. Is that correct? It's automatically deduped no matter what you do. It just you can, you know, understand that it will be that way. Nice. Automatically deduped.

Wes Bos

Yes. Array sets are still an array is something where you want where the order matters. Right.

Wes Bos

And same with sets. It's based on insertion order. However, you cannot sort a set.

Wes Bos

So the order of a set is The order at which you put the data in, which is similar to an object. People always say you can't guarantee the order of an object, but An object is always based on insertion order. There's a couple more rules around keys and number keys and object and symbol keys. But Mostly when you put them into the object, they go to the bottom. Same thing with sets is they go to the end of the actual set API, very simple. Get add. So it's add, not set. Set. Set would be a bit odd as clear and delete. It's just a really nice API. You don't have to check for includes.

Wes Bos

It's really easy to delete something. So let's say you have an array of comments and you want to delete a specific comment.

Wes Bos

You can simply just call delete and you pass it the reference to the comment and it will remove it. You don't have to know where in the set That item is, which can sometimes be a little bit annoying, or you're doing this like weird spread before, Skip 1, spread after.

Wes Bos

There's some new methods coming to JavaScript Arrays that will allow us to take items out of an array Much easier, but this API is onions. It's onions.

Wes Bos

It's apparently faster. So, again, the MDN docs say the has method checks if a value is in the set using an approach that is, on average, quicker than testing Most of the elements that have previously been added to the set, and particularly this is on average faster than array includes when an array has a length equal to a set size. So that's the other weird thing is that arrays have a length.

Wes Bos

Sets have a size.

Wes Bos

There's probably some meeting that went on and like many long GitHub threads on Should we use .length or .size? But Yeah. That's one thing to remember is it's not .length. It's it's .size, which is a property of how many items are in the set. Yeah.

Topic 8 17:31

When to use sets

Scott Tolinski

So okay. So this all sounds really great, but, like, when specifically do you reach for a set? You're you're thinking, I'm gonna put this into an array. Oh, wait. Maybe I should be using sets here, because I heard about it on Syntex.

Scott Tolinski

What is the specific use case where You might reach for a set specifically.

Wes Bos

Yeah. I think for me, it's when you simply want to Have a data bucket like you said with the maps. It's more for just holding hunks of data and you want a nice API.

Wes Bos

And probably something that you might not have considered is this is not just like a different type of array where, Oh, it doesn't have there's no find. There's no filter. There's no reduce. So like, okay, well, if I'm buying into set now, you're telling me I can't filter or find or reduce any of these type of things.

Wes Bos

It's much more primitive than that, but a lot of the new and upcoming Web APIs are being built on top of sets, and I think that, again, this is a very nice primitive in our language. If you're trying to build your own object or set that has a really nice API to it. Set is a really good standing point starting point for it. So the font face API, If you want to load a custom font into a website with JavaScript, not CSS.

Wes Bos

You can use the font face API and that is based on a set and it has the whole add, delete, has all of those methods that you're used to for checking if a font is loaded, if a font should be removed.

Wes Bos

So it's kind of neat to see, okay, these primitives are now being built upon now that they're in the browser.

Wes Bos

Browser vendors can use these primitives and all the performance stuff that comes along with it to build other things with it. Graphics as well.

Wes Bos

Like, let's say you have, like, a bunch of pixels and you want to check. All right. Is this value somewhere in this set? Makes a lot more sense to possibly use a set or there's also like U42 int arrays as well in graphics world. But This gets into alternative data structures when you are really counting on big jobs and big performance, which is often seen in data science

Scott Tolinski

and graphics processing. Yeah. I think a part of that too is that that the fact that values are unique Inside of a set, I think that's, like, the biggest thing. Right? Because you could think if you have, like like, you were saying the pixels a 2nd ago. I think there are times when An array makes way more sense than. Right? Let's say you have an array, and that array is here's 10 pixels.

Topic 9 20:24

Unique set values and use cases

Scott Tolinski

And in those 10 pixels, it's the background color of those 10 pixels. Right? I mean, you might have the same color multiple times. And then in that case, like I said, wouldn't wouldn't be appropriate because you need that array to be You do want it multiple times. Right. You want it multiple times. Not only that, but you wanna have a set a set size with, like I said, if you were to add another black to the set, it wouldn't add another one because the values need to be unique.

Wes Bos

So that's an interesting thing to think about here. On the the same idea, let's say you have a grid of 50 pixels or 50, like, spans. Every time you hover over one of those fans, it fills with a different color because you've highlighted it. So you might have a set which is called Highlighted pixels.

Wes Bos

And when you are rendering them out Yeah. You could say or when somebody hovers, you simply just add that You add that div or that span to the set as alright. That one's been hovered. And then when you're rendering them out, you say, alright. If this Pixel has been hovered, then do red.

Wes Bos

And in the case of adding, you don't have to check if it's already in there.

Wes Bos

And then in the case of rendering it out, you simply just say if Hover Dot has this Pixel, then pop a class on it Highlight it in a different way. Interesting.

Scott Tolinski

1 question I have is is you you mentioned spreading. You can spread them. I just wanna say definitively, you can spread them like you would in a ray. Correct? And, the process of transforming A set to an array could be done just by array brackets, dot, dot, dot, and then the set itself?

Wes Bos

Yes. Yes. So the spread syntax is for iterables, and iterables are things that you can loop over in JavaScript. So you cannot spread into a set.

Wes Bos

There are ways to add multiple items at once to a set. No problem there. But When you if you do want to take the items of a set and put them into an array, you can spread them.

Wes Bos

If you do want to Throw them into a function as a spread into arguments. You could do that as well. Sick.

Wes Bos

Last thing here is we also have weak versions of both of them. Weak map and weak set. So do these things just need to hit the gym? What's up with them? Yes. Why are we weak? Where's the soundboard? Weak.

Scott Tolinski

Weak. Weak. Weak. Weak.

Topic 10 22:52

Weak maps and sets

Wes Bos

So the weak versions of each of them is you can still add things to them. You can still delete things to them. You can still check if an item is in your set or map, but stuff. You cannot look and see what is inside a week set or a week map at any time, and you cannot Iterate over the items of a week set or week map. And the whole idea behind that is, like, what is the benefit of this collection if I can't see what's in the collection? The benefit to that is they are garbage collected. So in JavaScript, garbage collection is when a Value is no longer referenced anywhere in your code.

Wes Bos

The browser comes along and says, I'm going to get rid of this. I'm going to throw this in the garbage. I don't need it. So I have a variable called name and I set it to Scott.

Wes Bos

And then You click some buttons. You run some functions.

Wes Bos

That name variable is no longer needed anywhere. Nowhere is pointing to that variable. The browser says, all right, well, I got this name variable sitting on the shelf over here. It's taking up memory.

Wes Bos

I don't need that anymore. So it It throws it out. It's garbage collected. Right? So with week set and week maps, because you can put items into a map as a key, or you can put items into a set as a value itself.

Wes Bos

When those Values are no longer referenced anywhere in your code.

Wes Bos

They will be removed. So a good example is the counting clicks on a button that I talked about at the very top of the hour.

Wes Bos

If I was counting clicks with a map And somebody removes that div or that button from the page, that is still that whole button still sticks around in memory because I've referenced it somewhere. I've referenced it in my map.

Wes Bos

That's what that's what a memory leak is, is when you are referencing you're accidentally referencing some sort of object or value in the browser and it's deleted, but you're still referencing it. The browser doesn't know to clean that up and you run that long enough, you iterate over enough things. It happens more often enough, You run out of memory on your user's computer. Right? So with a weak set and a weak map, as soon as those values are no longer referenced, In my example, as soon as the button is no longer on the page, it's no longer in a variable somewhere. It's no longer being referenced by Anything else in your application, it's gone from the weak set or weak map as well, and you don't have to explicitly go and delete them From your map or set, they're just garbage collected. So let me let me understand if I I got this correct. So you could think of them as, like,

Scott Tolinski

a box. Right? You put something into a box.

Scott Tolinski

I can ask that box.

Scott Tolinski

Hey. Is okay. I'll I'll put my ChapStick into the box. Okay? Yep. I can ask the box, hey. Is my ChapStick in there? And the box will say yes or Yep. No.

Scott Tolinski

Or I can remove my ChapStick from the box, but I cannot open up the box and look at my ChapStick. Is that correct? Exactly. You say, hey. Do you have a ChapStick?

Wes Bos

Can you delete my Chapstick? Can you give me information about how many times I've clicked on my Chapstick? And can you can you delete everything from the box itself? You can do all of those things, but you cannot say give me a list of the things you have in the box, And you cannot open the box up and see everything that is in the box. There's no way for you to know what is in there.

Scott Tolinski

I think it helps that I don't use these things. So definitely, like, listening to you talk about them, it it's Yeah. Turning wheels in my brain about, like, alright. These are things that I haven't had to think about. Me erase objects, that's where I live. So, I think this episode was really enlightening For me to understand why these things exist and when you might wanna pick them up. And and personally, I think I I think sets seem really useful to me, and they all seem really useful to me. But, like, stuff. Mhmm. I think I think I'll start picking some of these up when they are appropriate

Wes Bos

because, hey, that's why they exist. Right? Yeah. If if you also like these are, I think, lower level primitives, like I've said. So if you look in the React source code, you're going to see maps all over the place because React needs to reference dom elements quite a bit. You know, it needs to keep data about what's on the page, what needs to be re rendered. Those are great use cases for sets and maps. So if if you look into any of these, like, lower level libraries,

Scott Tolinski

they're used quite a bit. Sick. Well, that was really enlightening. I I appreciate the, the the deep dive on this one, Wes. I think this this kind of stuff rules. Yeah. Thank you. Alright. Catch you later, everyone. Peace.

Scott Tolinski

Peace. Head on over to syntax.fm for a full archive of all of our shows, And don't forget to subscribe in your podcast player or drop a review if you like this show.

Share

Play / pause the audio
Minimize / expand the player
Mute / unmute the audio
Seek backward 30 seconds
Seek forward 30 seconds
Increase playback rate
Decrease playback rate
Show / hide this window