The JavaScript Map Type

The map data type is simple to understand and use but the topic can cause confusion due to the wide variety of names used to refer to the same thing. On top of that JavaScript did not have its own map type until ES6 came along we we had to improvise with an ordinary Object.

In this post I will run through what a map is before using both an Object and an ES6 Map.

The data structure generally referred to as a map in JavaScript, especially since the ES6 Map type was introduced, is also known as a dictionary or associative array, and sometimes as a hash table or hash. These last two names are somewhat misleading as they refer to one of the possible underlying implementations rather than the abstract set of behaviours.

A map is a collection of key/value pairs, or in other words a collection of names or labels used to refer to the corresponding data values. Within a map each key must be unique. The following operations are the minimum that need to be available although typically implementations provide more.

  • Insert new pairs
  • Delete existing pairs
  • Editing existing pairs
  • Reading the value of a given key

The JavaScript Map type also provides the following functionality:

  • Get the number of entries
  • Remove all entries in a single operation
  • Get the key/value pairs
  • Get the keys
  • Get the values
  • Check whether a key exists
  • A forEach function to run a function on all entries

The Project

This is a quick and simple project which gives a very brief demo of the traditional Object-based map, and then a more comprehensive demo of the ES6 Map type in action.

You can download the source code as a ZIP or from the Github repository using the links below.

Source Code Links

ZIP File
GitHub

The JavaScript lives in a file called map.js, and this is the first part of that file.

map.js part 1 of 2

window.onload = function()
{
    useObjectAsMap();

    // useMap();
}

function useObjectAsMap()
{
    const jaguars = {};

    jaguars.XK120 = 1948;
    jaguars.XK140 = 1954;
    jaguars.XK150 = 1957;

    const keys = Object.keys(jaguars);

    writeToConsole(`size: ${keys.length}<br/><br/>`, "console");

    for(key of keys)
    {
        writeToConsole(`Model: ${key} Year:${jaguars[key]}<br/>`, "console");
    }
}

As you can see the useObjectAsMap function is called in window.onload while the second function, useMap which we'll see later, is commented out.

The useObjectAsMap function is very straightforward: it just creates an Object and then adds a few properties to emulate a map data structure. I have then retrieved the object's keys to print out the size and key/value pairs.

There is nothing inherently wrong with this approach and no doubt it has been used millions of times. However, it isn't perfect and the ES6 Map provides a more optimized implementation.

If you open map.htm in your browser you'll see something like this.

Now let's look at the useMap function.

map.js part 2 of 2

function useMap()
{
    const jaguars = new Map();

    jaguars.set("XK120", 1948);
    jaguars.set("XK140", 1954);
    jaguars.set("XK150", 1957);

    writeToConsole(`size: ${jaguars.size}<br/><br/>`, "console");

    writeToConsole(`has XK140? ${jaguars.has("XK140")}<br/>`, "console");
    writeToConsole(`has E-Type? ${jaguars.has("E-Type")}<br/><br/>`, "console");

    for(let jaguar of jaguars.entries())
    {
        writeToConsole(`${jaguar}<br/>`, "console");
    }

    writeToConsole("<br/>", "console");

    for(let key of jaguars.keys())
    {
        writeToConsole(`${key}: ${jaguars.get(key)}<br/>`, "console");
    }

    writeToConsole("<br/>", "console");

    for(let value of jaguars.values())
    {
        writeToConsole(`${value}<br/>`, "console");
    }

    writeToConsole("<br/>", "console");

    jaguars.delete("XK120");
    writeToConsole(`size: ${jaguars.size}<br/><br/>`, "console");

    jaguars.clear();
    writeToConsole(`size: ${jaguars.size}<br/>`, "console");
}

This code should be self-explanatory but a few additional notes might be helpful.

  • Key/value pairs are added with the set method.
    Code such as
    jaguars["XK120"] = 1948; // WRONG!
    does not cause an error but also does not add the item to the Map.

  • I have used strings as keys but perhaps surprisingly you can use anything, including objects and functions. I haven't had the opportunity to use a function as a key yet but hope to some day. Software developers have some strange ambitions.

  • The number of items is retrieved using the size method. length will return 0.

  • We can check for the presence of a key using has.

  • You can get the key/value pairs, and therefore iterate the Map, using the entries method.

  • You can also get the keys or values separately using keys and values respectively.

  • If you have a key you can read the corresponding value with the get method.

  • It is also possible to iterate the entries using
    for (let [key, value] of jaguars)

  • The entries are returned by the iterators in the order they were inserted.

  • You can remove a single entry with the delete method.

  • You can remove all entries with the clear method.

  • Aside from being more intuitive to use than an Object, the Map provides improved performance for frequent set and delete operations.

If you comment out useObjectAsMap and uncomment useMap in window.onload and then refresh the page you will see the results of the various operations on our Map object.

Looking for a VPN?

StrongVPN is running a promotion where customers can get a permanent discount on the monthly plan for just $5 for life! Ends June 30, 2020.