JavaScript Map - Exercise 2
The forEach() method executes a callback function for each key-value pair in the Map. The callback receives three arguments: the value, the key, and the Map itself.
const userRoles = new Map([
['alice', 'admin'],
['bob', 'editor'],
['charlie', 'viewer']
]);
// Using forEach to iterate
userRoles.forEach((value, key) => {
console.log(`${key}: ${value}`);
});
// Output:
// alice: admin
// bob: editor
// charlie: viewer
The keys() method returns an iterator containing all the keys in the Map. You can use this iterator with a for...of loop or convert it to an array.
const prices = new Map([
['apple', 1.5],
['banana', 0.75],
['orange', 2.0]
]);
// Iterate over keys
for (const fruit of prices.keys()) {
console.log(fruit);
}
// Output:
// apple
// banana
// orange
// Convert keys to an array
const fruitNames = [...prices.keys()];
console.log(fruitNames); // ['apple', 'banana', 'orange']
The values() method returns an iterator containing all the values in the Map. This is useful when you only need to work with the values and do not need the keys.
const scores = new Map([
['math', 95],
['science', 88],
['english', 92]
]);
// Iterate over values
for (const score of scores.values()) {
console.log(score);
}
// Output:
// 95
// 88
// 92
// Calculate total using values
const total = [...scores.values()].reduce((sum, val) => sum + val, 0);
console.log(total); // 275
The entries() method returns an iterator of key-value pairs as arrays. Each entry is a two-element array where the first element is the key and the second is the value.
const inventory = new Map([
['shirts', 50],
['pants', 30],
['shoes', 25]
]);
// Iterate over entries
for (const entry of inventory.entries()) {
console.log(entry);
}
// Output:
// ['shirts', 50]
// ['pants', 30]
// ['shoes', 25]
// Destructure entries while iterating
for (const [item, count] of inventory.entries()) {
console.log(`${item}: ${count} in stock`);
}
Maps are iterable by default, so you can use a for...of loop directly on a Map. Each iteration yields a key-value pair as an array, which you can destructure for cleaner code.
const capitals = new Map([
['France', 'Paris'],
['Japan', 'Tokyo'],
['Brazil', 'Brasilia']
]);
// Direct iteration with for...of
for (const pair of capitals) {
console.log(pair); // ['France', 'Paris'], etc.
}
// Destructuring in for...of loop
for (const [country, city] of capitals) {
console.log(`The capital of ${country} is ${city}`);
}
// Output:
// The capital of France is Paris
// The capital of Japan is Tokyo
// The capital of Brazil is Brasilia
You can convert a Map to an array using the spread operator or Array.from(). This creates an array of key-value pairs. You can also convert just keys or values to arrays separately.
const colors = new Map([
['red', '#FF0000'],
['green', '#00FF00'],
['blue', '#0000FF']
]);
// Convert to array of pairs using spread
const pairsArray = [...colors];
console.log(pairsArray);
// [['red', '#FF0000'], ['green', '#00FF00'], ['blue', '#0000FF']]
// Using Array.from()
const pairsArray2 = Array.from(colors);
// Convert only keys to array
const keysArray = [...colors.keys()];
console.log(keysArray); // ['red', 'green', 'blue']
// Convert only values to array
const valuesArray = [...colors.values()];
console.log(valuesArray); // ['#FF0000', '#00FF00', '#0000FF']
You can create a Map from an array of key-value pairs by passing the array to the Map constructor. Each inner array should have exactly two elements representing the key and value.
// Array of key-value pairs
const pairsArray = [
['name', 'Alice'],
['age', 30],
['city', 'New York']
];
// Convert array to Map
const personMap = new Map(pairsArray);
console.log(personMap.get('name')); // 'Alice'
console.log(personMap.get('age')); // 30
console.log(personMap.size); // 3
// Works with any iterable of pairs
const entries = [['a', 1], ['b', 2]];
const letterMap = new Map(entries);
console.log(letterMap); // Map(2) { 'a' => 1, 'b' => 2 }
Use Object.entries() to get an array of key-value pairs from an object, then pass it to the Map constructor. This converts all enumerable string-keyed properties to Map entries.
const userObj = {
name: 'Bob',
email: 'bob@example.com',
role: 'admin'
};
// Convert object to Map using Object.entries()
const userMap = new Map(Object.entries(userObj));
console.log(userMap.get('name')); // 'Bob'
console.log(userMap.get('email')); // 'bob@example.com'
console.log(userMap.size); // 3
// Verify the conversion
for (const [key, value] of userMap) {
console.log(`${key}: ${value}`);
}
// name: Bob
// email: bob@example.com
// role: admin
Use Object.fromEntries() to convert a Map to a plain object. Note that this only works properly when all Map keys are strings or symbols, since object keys must be strings or symbols.
const settingsMap = new Map([
['theme', 'dark'],
['language', 'en'],
['notifications', true]
]);
// Convert Map to object using Object.fromEntries()
const settingsObj = Object.fromEntries(settingsMap);
console.log(settingsObj);
// { theme: 'dark', language: 'en', notifications: true }
console.log(settingsObj.theme); // 'dark'
console.log(settingsObj.language); // 'en'
// Warning: Non-string keys are converted to strings
const mixedMap = new Map([[1, 'one'], [2, 'two']]);
const mixedObj = Object.fromEntries(mixedMap);
console.log(mixedObj); // { '1': 'one', '2': 'two' }
You can create a shallow copy of a Map by passing the original Map to the Map constructor. Changes to the copy will not affect the original Map, but nested objects are still shared between them.
const original = new Map([
['a', 1],
['b', 2],
['c', 3]
]);
// Create a copy by passing Map to constructor
const copy = new Map(original);
// Modify the copy
copy.set('d', 4);
copy.delete('a');
console.log(original); // Map(3) { 'a' => 1, 'b' => 2, 'c' => 3 }
console.log(copy); // Map(3) { 'b' => 2, 'c' => 3, 'd' => 4 }
// Note: This is a shallow copy
const mapWithObj = new Map([['user', { name: 'Alice' }]]);
const shallowCopy = new Map(mapWithObj);
shallowCopy.get('user').name = 'Bob';
console.log(mapWithObj.get('user').name); // 'Bob' (shared reference)
You can merge Maps by spreading them into a new Map constructor. If both Maps have the same key, the value from the later Map will overwrite the earlier one.
const defaults = new Map([
['theme', 'light'],
['fontSize', 14],
['language', 'en']
]);
const userPrefs = new Map([
['theme', 'dark'],
['fontSize', 16]
]);
// Merge Maps using spread operator
const merged = new Map([...defaults, ...userPrefs]);
console.log(merged);
// Map(3) { 'theme' => 'dark', 'fontSize' => 16, 'language' => 'en' }
// Later values overwrite earlier ones
console.log(merged.get('theme')); // 'dark' (from userPrefs)
console.log(merged.get('language')); // 'en' (from defaults)
// Merge multiple Maps
const map1 = new Map([['a', 1]]);
const map2 = new Map([['b', 2]]);
const map3 = new Map([['c', 3]]);
const combined = new Map([...map1, ...map2, ...map3]);
Maps can use objects as keys and distinguish between different object references. Regular objects convert all keys to strings, so different objects become the same key. This makes Maps ideal for associating data with specific object instances.
const user1 = { id: 1, name: 'Alice' };
const user2 = { id: 2, name: 'Bob' };
// Map keeps object keys separate
const userScores = new Map();
userScores.set(user1, 100);
userScores.set(user2, 85);
console.log(userScores.get(user1)); // 100
console.log(userScores.get(user2)); // 85
console.log(userScores.size); // 2
// Regular object converts keys to strings
const objScores = {};
objScores[user1] = 100;
objScores[user2] = 85;
console.log(Object.keys(objScores)); // ['[object Object]']
console.log(objScores[user1]); // 85 (overwritten!)
// Map is perfect for metadata on objects
const metadata = new Map();
metadata.set(document.body, { clicks: 0 });
metadata.set(window, { resizes: 0 });