JavaScript Map is getting upsert!

Laurie - May 19 '20 - - Dev Community

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' }
Enter fullscreen mode Exit fullscreen mode

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

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

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()
Enter fullscreen mode Exit fullscreen mode

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()
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

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!

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .