The standard JavaScript Map class is a general-purpose utility class for associating any kind of value with any kind of key.
const primes = new Map();
primes.set(3, true);
primes.set(4, false);
primes.get(3); // true
primes.get(4); // false
Uses for Map overlap somewhat with uses for plain objects and arrays. Unlike those types of objects, you can extend the Map class to override its basic operations like get().
This lets you create a custom class that looks and works like Map, but whose internal implementation may be quite different. This uses the Map class as an interface: a defined set of consistently-named methods and properties that meet specific expectations.
Example #
It’s possible, for example, to create a Map subclass that wraps the active set of environment variables using Node’s process.env API.
import process from "node:process";
export default class EnvMap extends Map {
// Get a specific environment variable
get(key) {
return process.env[key];
}
// Return the set of environment variable names
*keys() {
yield* Object.keys(process.env);
}
}
This lets you retrieve an environment variable using a get() call:
const m = new EnvMap();
m.get("PATH"); // returns the user's current PATH variable
Note that this sample Map subclass isn’t copying data into a Map — it’s wrapping an existing set of data as a Map. This bypasses the Map class’ built-in storage system to retrieve data directly from the environment.
Advantages of Map #
Using the Map class as an interface makes it possible to create a set of useful, general purpose operations that can process data represented in a wide variety of ways: filtering, grouping, sorting, and so on.
Instead of having to develop specific versions of these operations for objects, arrays, files, etc., all those data types can be represented as Map objects. The operations can then be written to work with Map objects.
The standard Map class is somewhat awkward to extend directly. For this reason, the async-tree library includes a base class called SyncMap that can be used as a drop-in replacement for Map. See that page for a discussion of the issues with Map and how SyncMap addresses them.
Another important use of Map is in constructing general-purpose trees, such as the tree of resources for a site. See the Map Tree pattern for a walkthrough of how maps can be used in that way.
Asynchronous maps #
The standard Map class has synchronous methods. To represent asynchronous data sources, the async-tree library defines a AsyncMap class as a variation.
AsyncMaphas with the same basic interface asMap, but the methods and properties are all async.- Additionally, instead of defining a
Symbol.iteratorproperty,AsyncMapdefines anSymbol.asyncIterator.
All of the Tree builtins accept both Map and AsyncMap objects.
Map-based trees #
If a value in a Map is another Map, you can view the overall structure as a map-based tree.