Skip to content
Theory · Map, Set and JSON · lesson 1 of 9

The Map collection

What you'll learn

What you'll learn:

  • store key–value pairs in a Map and count words with it;
  • collect values without repeats in a Set;
  • turn an object into a JSON string and back, and know what gets lost;
  • explain in an interview how a Map differs from a plain object.
A coat rail Map with two hooks and two coats, the discs 1 and '1' being two different keys

Picture a theater cloakroom. You hand over your coat, and the attendant gives you a token. The token is the key, the coat is the value. After the show you present the token and get your coat back.

An object in JavaScript also stores key–value pairs, but it has a quirk: it turns a number used as a key into a string. It is like an attendant who reads every token as text. For them the token 1 and the token "1" are one and the same hook. Let's see:

JavaScript
const names = {};
names[1] = "one";
names["1"] = "uno";
console.log(Object.keys(names).length); // 1

const map = new Map();
map.set(1, "one");
map.set("1", "uno");
console.log(map.size); // 2
console.log(map.get(1), map.get("1")); // one uno

Let's go step by step:

  1. names[1] = "one" writes the key "1" into the object: the number became a string.
  2. names["1"] = "uno" writes under the same key and replaces "one".
  3. That is why the object has one key, and the program prints 1.
  4. In the second half the Map keeps 1 and "1" as two different keys: size is 2.

What a Map is

Map is a built-in collection of key–value pairs. A collection is a value that holds many other values inside it. A key in a Map stays exactly as it was passed: a number, a string, true or an object.

The expression new Map() creates an empty collection, and the word new in it is required. new creates a new value — here a new empty collection. Without it, the call Map() throws a TypeError.

Map methods

You work with a Map through methods, not through map.key or map[key] as with an object:

  • map.set(key, value) stores a value under a key, and for an existing key replaces the old value;
  • map.get(key) returns the value, or undefined if there is no such key;
  • map.has(key) returns true or false;
  • map.delete(key) removes a pair;
  • map.size holds the number of pairs — it is a property, so no parentheses follow it.

A Map has no length property, and map.length gives undefined.

JavaScript
const stock = new Map();
stock.set("apple", 3);
stock.set("pear", 5);
stock.set("apple", 4);
stock.delete("pear");

console.log(stock.get("apple"), stock.get("plum")); // 4 undefined
console.log(stock.has("pear"), stock.size); // false 1

const ann = { name: "Ann" };
const visits = new Map();
visits.set(ann, 2);
console.log(visits.get(ann), visits.get({ name: "Ann" })); // 2 undefined

Let's walk through the stock warehouse:

  1. The first two set calls put in apples and pears.
  2. The third set with the key "apple" adds no pair; it replaces 3 with 4.
  3. delete("pear") removes the pears.
  4. So get("apple") gives 4, and get("plum") gives undefined: there are no plums in stock.
  5. has("pear") gives false, and size is 1.

An object as a key

An object key is compared by reference. get finds the value only through the very same object. Another object with the same properties is a different key, so visits.get({ name: "Ann" }) gives undefined.

This is where the cloakroom analogy stops working. A real attendant looks at the number on the token, and a copy with the same number would work too. A Map with an object key recognizes only that very token, not a copy of it.

Counting with a Map

A common task is to count how many times each word occurs. For this, get is combined with the ?? operator: counts.set(word, (counts.get(word) ?? 0) + 1). If the key is not there yet, get returns undefined, ?? replaces it with 0, and 1 is stored under the key.

Press "Next step" and watch old: for a new word it is 0, and for a known one it is the previous count.

LiveCounting words in a Mapstep 1 of 10 · frames: 1

The collection counts is created, and it holds no pairs yet.

get takes the old count, set stores the new one

Each word holds its count, and size is the number of different words.

Iterating over a Map

A Map remembers the order in which its keys were added. A for…of loop goes over the pairs in exactly that order. Each pair is an array [key, value], which destructuring takes apart conveniently:

JavaScript
const scores = new Map();
scores.set("Bob", 7);
scores.set("Ann", 9);
scores.set(10, 1);

for (const [key, value] of scores) {
    console.log(key, value);
}
// Bob 7
// Ann 9
// 10 1

The key 10 stayed last, although in an object an integer-like key would have moved to the front. The expression [...scores] uses spread syntax to turn a Map into an array of such pairs.

A Map or an object

Interviewers like to ask this: "How does a Map differ from an object?" The answer has three parts:

  • a Map key can be any value, while an object turns a number into a string;
  • a Map remembers the order keys were added in and keeps the number of pairs in size;
  • you work with a Map through get, set, has and delete.

An object suits data with properties known in advance, such as user.name and user.age. A Map suits a dictionary whose keys appear while the program runs: words from a text, order numbers, objects.

Common mistake

A value was written into a Map with square brackets, as into an object:

JavaScript
const stock = new Map();
stock["apple"] = 3; // ✗

console.log(stock.get("apple"), stock.size); // undefined 0

There is no error, but the pair never reached the collection. The brackets created an ordinary property on the object stock, and get and size do not see it. Store pairs only through set: stock.set("apple", 3).

Key points

  • A Map stores key–value pairs, and a key stays exactly as it was passed: 1 and "1" are different keys.
  • Pairs are written with set and read with get, and size holds their number.
  • An object key is looked up by reference: only the very same object matches.
  • For counting, write counts.set(word, (counts.get(word) ?? 0) + 1).

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way