loading...
Cover image for JavaScript Map is getting upsert!

JavaScript Map is getting upsert!

laurieontech profile image Laurie Originally published at laurieontech.com ・2 min read

This post originally appeared on laurieontech.dev

Let's introduce a new (potential) piece of syntax in JavaScript!

What is Map?

Map is a data structure in JavaScript that you may not have heard of! When you think of map, you probably think of Array.prototype.map.

But Map is different. A Map is an object in JavaScript that holds key-value pairs.

Wait a second...how is that different than an Object?!

They have some similarities. In fact, it was not uncommon to use an Object in place of a Map before Maps were added to the language. However, there are also differences, mainly:

  • A Map has no prototype, so there are no keys at all unless you create them
  • Map keys can be anything, including functions or objects
  • Map remembers the insertion order of your keys
  • Map comes with a size() function
  • Maps are Iterables
  • Maps can be more performant when frequently adding or removing key-value pairs

Adding values

You can create a Map and add key-value pairs using the set function.

let example = new Map()
example.set('test', 'value')
// example is Map { 'test' => 'value' }

However, if you set something with the same key, the value will be overwritten.

example.set('test', true)
// example is Map { 'test' => true }

If you want to operate on a specific key you need to make sure it's there, add it if it isn't, and then operate on it.

if (!example.has('test')) {
  example.set('test', 'new value')
}
example.get('test').myFunctionForMessingWithThisKeyEntry()

And this isn't the only situation like that. You may only want to insert a key if it's missing, only update if it's present, etc. It'd be nice to not have to do existence checks and use set and get all the time.

In comes upsert

upsert makes this easier!

upsert is a function on the Map prototype. It takes three arguments.

The first argument is the key that you want to use.

The second is the function you want to operate on the existing value, if found.

The third is what you want to happen if the key does not currently exist.

So our previous example becomes this.

example
  .upsert('test', undefined, () => 'new value')
  .myFunctionForMessingWithThisKeyEntry()

In this case, we're leaving the existing value alone if it already exists, thus the undefined.

Alternatively, we have this example.

example.upsert('test', old => old.someOperation(), undefined)

Here, old is equivalent to map.get('test'), and we're operating on it. If the key doesn't exist, we do nothing.

Seeing these two examples it becomes clear that there are a number of different possibilities for using upsert.

TC39 Stage 2

This proposal is currently in Stage 2 of the TC39 process. If you're interested in participating in that conversation, please do!

Posted on by:

laurieontech profile

Laurie

@laurieontech

Software dev at Gatsby | DC techie | Conference speaker | egghead Instructor | TC39 Educators Committee | Girls Who Code Facilitator | Board game geek | @laurieontech on twitter

Discussion

markdown guide
 

Is this different than assigning new values with spread operator?

 

The spread operator is not valid inside Map's set function so far as I am aware.

 

Thanks for share it, that is a very good addition. One question:

What do you mean by Map doesn't have prototype at all ?

I did a little test on my machine an got this

image

 

I believe he misspoke. His comparison was that, when using a plain Object as a map, you have to worry about the keys from the prototype chain. When using a Map, there are no keys already defined in the Map. A Map object is still and object and still uses the prototype chain to define itself.

 

Wait... this is stage 2 so it's not out yet right?

 

Yup! That’s why I note it as a potential piece of syntax.

 
 

Very nice :). Looks quite convenient!

 

So cool, that’s for the post!