JavaScript Map is getting upsert!

May 19, 2020

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 does not contain any keys by default
  • Map keys can be anything, including functions or objects
  • Map remembers the insertion order of your keys
    • Note that Objects do this as of ES2015
  • 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!


A blog by Laurie Barth.
Teacher of all things tech.