This lesson is the full Map toolkit: every method, the ways to loop, how to convert between Maps, objects, and arrays, and Map.groupBy for sorting data into buckets.
| Member | Does | Returns |
|---|---|---|
| set(key, value) | Add or replace | the Map |
| get(key) | Look up a value | value or undefined |
| has(key) | Check a key exists | true / false |
| delete(key) | Remove a pair | true if it existed |
| clear() | Remove everything | undefined |
| size | Property: number of pairs | number |
| forEach((value, key) => ...) | Run a function on each pair | undefined |
| keys() / values() / entries() | Iterators for looping | iterator |
const grades = new Map()
.set("A", 90)
.set("B", 80)
.set("C", 70);
const fruits = new Map([["apples", 500], ["bananas", 300]]);
console.log(fruits.has("apples"));
console.log(fruits.delete("apples"), fruits.delete("apples")); // removed, then nothing to remove
console.log(fruits.has("apples"));
fruits.clear();
console.log(fruits.size);
A missing key returns undefined. Pair get with ?? to supply a default:
const nicknames = new Map([["Robert", "Bob"]]);
nicknames.get("Robert") ?? "(none)" // "Bob"
nicknames.get("Ada") ?? "(none)" // "(none)"
const ages = new Map([["Ava", 16], ["Ben", 17]]);
for (const [name, age] of ages) { } // pairs (most common)
for (const name of ages.keys()) { } // keys only
for (const age of ages.values()) { } // values only
ages.forEach((age, name) => { }); // note: value comes FIRST
forEach, the callback gets (value, key), value first. In for...of with destructuring, you get [key, value], key first. Mixing them up swaps your data silently.
entries() gives the same [key, value] pairs as looping the Map directly. values() is handy for totals:
const stock = new Map([["apples", 500], ["bananas", 300], ["oranges", 200]]);
let total = 0;
for (const qty of stock.values()) {
total += qty;
}
console.log(total);
const m = new Map([["x", 1], ["y", 2]]);
// Map to array of pairs / keys / values
[...m] // [["x", 1], ["y", 2]]
[...m.keys()] // ["x", "y"]
[...m.values()] // [1, 2]
// Map to plain object (string keys only)
Object.fromEntries(m) // { x: 1, y: 2 }
// Plain object to Map
new Map(Object.entries({ a: 1, b: 2 })) // Map(2) {"a" => 1, "b" => 2}
JSON.stringify(map) gives "{}": JSON does not understand Maps. Save JSON.stringify([...map]) instead, and rebuild with new Map(JSON.parse(text)).
const apples = { name: "Apples" };
const prices = new Map([[apples, 500]]);
console.log(prices.get(apples));
console.log(prices.get("apples"));
console.log(prices.get({ name: "Apples" }));
"apples" is a different key, and so is a new object that only looks the same. Keep a variable pointing to the key object if you want to look it up later.
Maps have no map or filter of their own. Spread into an array of pairs, transform, and build a new Map:
const prices = new Map([["pen", 2], ["book", 15], ["bag", 30]]);
const onSale = new Map(
[...prices].map(([item, price]) => [item, price * 0.5])
);
const pricey = new Map(
[...prices].filter(([item, price]) => price > 10)
);
console.log(onSale.get("bag"), [...pricey.keys()]);
Added in 2024, Map.groupBy takes a list and a function. The function's return value decides which group each item goes into:
const students = [
{ name: "Ava", grade: 10 },
{ name: "Ben", grade: 11 },
{ name: "Cal", grade: 10 },
{ name: "Dee", grade: 12 }
];
const byGrade = Map.groupBy(students, s => s.grade);
for (const [grade, group] of byGrade) {
console.log(grade, group.map(s => s.name));
}
Notice the keys stayed numbers. With a plain object they would have become strings.
The callback can return any value to use as the group name, such as a label worked out with a ternary:
const inventory = [
{ name: "apples", quantity: 300 },
{ name: "bananas", quantity: 500 },
{ name: "oranges", quantity: 200 },
{ name: "kiwi", quantity: 150 }
];
const byStock = Map.groupBy(inventory, item => item.quantity > 200 ? "ok" : "low");
console.log(byStock.get("low").map(i => i.name));
Object.groupBy does the same grouping but returns a plain object. Its group names become strings, so Object.groupBy(students, s => s.grade) gives keys "10", "11", "12". Use Map.groupBy when the group keys should keep their type or be objects. Neither one changes the original array.
What does this log?
const m = new Map([["a", 1]]);
m.forEach((x, y) => console.log(x, y));
1 a. forEach passes the value first, then the key, whatever you name the parameters.What does JSON.stringify(new Map([["a", 1]])) give?
'{"a":1}''[["a",1]]''{}'[...map] instead.What does this log?
const k = { id: 1 };
const m = new Map([[k, "yes"]]);
console.log(m.get(k), m.get({ id: 1 }));
yes undefined. Object keys are matched by identity. { id: 1 } in the second call is a brand-new object, so it is not the key.set, then loop the Map with both for...of and forEachMap.groupBy to group the words of a sentence by their length