JavaScript Map object and Array.map() explained

The JavaScript map keyword covers two related but distinct things: the Map object, which is a data structure for storing key-value pairs, and Array.prototype.map(), a method that transforms arrays. This guide covers both fully. You’ll learn how to create and work with the Map object using methods like set(), get(), delete() and has(), how to iterate over it, and how Array.map() works as a non-mutating array transformer. By the end, you’ll also know exactly when to pick Map over a plain object.

What is map in JavaScript?

In JavaScript, “map” refers to two different things depending on context. The Map object (capital M) is a built-in keyed collection added in ES6 (ECMAScript 2015). It stores key-value pairs, remembers the insertion order of those entries and accepts any value as a key: objects, functions, numbers or strings. The Array.prototype.map() method (lowercase m) is something different: a functional method that takes an array, runs a callback over each element and returns a new array of the same length containing whatever the callback returned.

Map vs Object: when to use each

Before reaching for a plain JavaScript object to store key-value data, it’s worth knowing where Map differs. The JavaScript Array and object are both common defaults, but Map exists because objects have limitations.

MapObject
Key typesAny typeStrings and Symbols only
Insertion orderPreserved, alwaysComplex, not always reliable
Sizemap.size propertyManual (Object.keys(obj).length)
IterationDirectly iterable (for...of)Not directly iterable by default
Default keysNonePrototype keys can collide
PerformanceOptimized for frequent add/removeNot optimized for frequent mutations
JSON supportNo native JSON.stringifyNative support

A plain object works fine when your keys are strings, your data is static and you need JSON serialization. Switch to Map when keys are objects or functions, when you need a guaranteed iteration order or when your application adds and removes entries frequently.

How to create a Map in JavaScript

There are two ways to create a Map: using the new Map() constructor with an initial array of key-value pairs, or starting with an empty map and adding entries via set().

1. The new Map() constructor

Pass an array of two-element arrays to new Map(). Each inner array becomes a [key, value] pair.

const fruits = new Map([
  ['India', 'New Delhi'],
  ['Australia', 'Canberra'],
  ['France', 'Paris']
]);

Elements in the array become key-value pairs, such as 'India' as the key and 'New Delhi' as its corresponding value.

2. The set() method

You can also start with an empty Map and add entries one at a time. The set() method accepts the key as the first argument and the value as the second, and it returns the Map itself so calls can be chained.

const Country = new Map();

Country.set('India', 'New Delhi');
Country.set('Australia', 'Canberra');
Country.set('France', 'Paris');
Country.set('Italy', 'Rome');

Here, an empty map is created using const Country = new Map(), and then with the set() method we add key-value pairs just like a JavaScript object. With every new Country.set() call, a new key-value pair is pushed into the map.

Now if we print the given map, we see all key-value pairs are added to a single map and all the keys are displayed alongside their value pairs.

console.log(Country);
JavaScript set() Method

The set() method also handles updates. If you call set() with a key that already exists, it overwrites the previous value rather than creating a duplicate entry. Map keys are guaranteed to be one-of-a-kind. Only one entry per key is allowed.

// Update an existing key
Country.set('India', 'Mumbai'); // overwrites 'New Delhi'

Essential Map methods in JavaScript

The JavaScript Map object provides a full set of instance methods and properties for working with key-value pairs. Here is each one with a working example.

1. The get() method

This method allows us to access the value of a particular key. It returns the value paired with the provided key, or undefined if the key doesn’t exist.

const Country = new Map();

Country.set('India', 'New Delhi');
Country.set('Australia', 'Canberra');
Country.set('France', 'Paris');
Country.set('Italy', 'Rome');

console.log(Country.get('France'));

Here it will return the value of 'France' which is 'Paris'.

JavaScript get() Method Output

2. The has() method

This method checks for a key’s existence. It returns true if the key is in the map and false if it isn’t.

const Country = new Map();

Country.set('India', 'New Delhi');
Country.set('Australia', 'Canberra');
Country.set('France', 'Paris');
Country.set('Italy', 'Rome');

console.log(Country.has('France'));
console.log(Country.has('Britain'));

Our map has 'France' so it returns true, and for 'Britain' it returns false because that key is absent.

JavaScript has() Method Output

3. The delete() method

This method removes a particular key along with its paired value. It returns true if the key was found and removed, and false if the key didn’t exist.

const Country = new Map();

Country.set('India', 'New Delhi');
Country.set('Australia', 'Canberra');
Country.set('France', 'Paris');
Country.set('Italy', 'Rome');

Country.delete('Australia');
console.log(Country);

Here, delete() removes 'Australia' from the map and then the updated map is displayed.

JavaScript delete() Method Output

4. The clear() method

This method removes all entries at once. After clear(), the map has zero entries.

const Country = new Map();

Country.set('India', 'New Delhi');
Country.set('Australia', 'Canberra');
Country.set('France', 'Paris');
Country.set('Italy', 'Rome');

Country.clear();
console.log(Country);

All keys are cleared from the map and an empty map is displayed.

JavaScript clear() Method Output

5. The size property

The size property returns the number of key-value entries currently in the map. It updates automatically as entries are added or removed.

const Country = new Map();

Country.set('India', 'New Delhi');
Country.set('Australia', 'Canberra');
Country.set('France', 'Paris');
Country.set('Italy', 'Rome');

console.log(Country.size);

An integer value 4 is returned.

JavaScript size() Method Output

Alternative way to see the size

const Country = new Map();

Country.set('India', 'New Delhi');
Country.set('Australia', 'Canberra');
Country.set('France', 'Paris');
Country.set('Italy', 'Rome');

console.log(Country);

If you look closely at the output of console.log(Country), there is a Map(4) prefix before the entries. The 4 here is the size of the map.

Alternative to size

Iterator methods: keys(), values() and entries()

Beyond the core CRUD methods, Map exposes three iterator methods that give you controlled access to either the keys, the values or both together.

keys()

Returns a new iterator over every key in insertion order.

const map = new Map([
  ['a', 1],
  ['b', 2],
  ['c', 3]
]);

for (const key of map.keys()) {
  console.log(key);
}
// a
// b
// c

values()

Returns a new iterator over every value in insertion order.

for (const value of map.values()) {
  console.log(value);
}
// 1
// 2
// 3

entries()

Returns a new iterator over [key, value] pairs in insertion order. This is also what Map[Symbol.iterator] produces by default, so iterating a Map directly with for...of is equivalent to calling entries().

for (const [key, value] of map.entries()) {
  console.log(`${key} = ${value}`);
}
// a = 1
// b = 2
// c = 3

Iterating through a Map in JavaScript

Iteration helps us process every key-value pair in a Map. You can use for...of or forEach to work through each entry. These iteration methods always follow insertion order. The first entry you added is the first one visited. This is something plain JavaScript objects historically didn’t guarantee.

1. Using for…of

The for...of loop iterates directly over a Map. Destructure each entry into [key, value] to access both at once.

Syntax:

for (let [key, value] of map) {
  console.log(key, value);
}

Example:

const map = new Map();

map.set('Google', 'Sundar Pichai ');
map.set('Meta', 'Mark Zuckerberg');
map.set('Microsoft', 'Satya Nadella');


for (let [key, value] of map) {
  console.log(`${key}: ${value}`);
}
JavaScript for…of Output

2. Using forEach

The forEach method calls a callback function for every entry. Notice that the parameter order here is (value, key), reversed compared to what you might expect from the array version. This is intentional per the spec and is a common source of bugs, so always double-check the order.

Syntax:

map.forEach((value, key) => {
  console.log(key, value);
});

Example:

const map = new Map();

map.set('Jupiter', 'Giant Among Giants');
map.set('Neptune', 'Blue Giant');
map.set('Saturn', 'Ringed Planet');

map.forEach((value, key) => {
    console.log(key, value);
  });
JavaScript forEach Output

Using functions as keys in JavaScript Map

When you assign a key to a map, it doesn’t need to be a plain string or number. You can use functions, arrays or any other object as a key. Under the hood, Map key comparison uses the SameValueZero algorithm. This means object identity: two different function references are two different keys even if they have the same code.

Quick Note: The function that needs to be added as a key should be defined first. Then you can assign values to it.

const square = function(num) {
    return num * num;
};

const cube = function(num) {
    return num * num * num;
};

const map = new Map();
map.set(square, 5);
map.set(cube, 3);

console.log(`Square of 5 is: ${square(map.get(square))}`);
console.log(`Cube of 3 is: ${cube(map.get(cube))}`);

If you carefully look at ${square(map.get(square))}, here we first get 5 from map.get(square), then square(5) results in 25.

Using Functions as Keys in JavaScript Map Output

Using objects as keys is one of the most practical advantages of Map over plain objects. A common production pattern is caching computed values keyed by the original object. Every lookup is O(1) and the key is the actual object reference, not a string ID you had to generate.

Cloning and merging Maps

Because Map accepts any iterable of [key, value] pairs in its constructor, you can clone an existing map by passing it directly.

const original = new Map([[1, 'one']]);

const clone = new Map(original);

console.log(clone.get(1)); // one
console.log(original === clone); // false

Note that this is a shallow copy. The keys and values themselves are not cloned.

Merging two maps uses the spread operator to flatten both into a combined array of pairs. When two maps share a key, the last one wins.

const first = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

const second = new Map([
  [1, 'uno'],
  [2, 'dos'],
]);

const merged = new Map([...first, ...second]);

console.log(merged.get(1)); // uno
console.log(merged.get(2)); // dos
console.log(merged.get(3)); // three

Map.groupBy(): static grouping method

ES2024 introduced Map.groupBy(), a static method that takes an iterable and a callback, and returns a Map where each key is a distinct value returned by the callback and each value is an array of all elements that produced that key.

const inventory = [
  { name: 'asparagus', type: 'vegetables', quantity: 5 },
  { name: 'bananas', type: 'fruit', quantity: 0 },
  { name: 'goat', type: 'meat', quantity: 23 },
  { name: 'cherries', type: 'fruit', quantity: 5 },
  { name: 'fish', type: 'meat', quantity: 22 },
];

const result = Map.groupBy(inventory, ({ type }) => type);

console.log(result.get('fruit'));
// [ { name: 'bananas', ... }, { name: 'cherries', ... } ]

This is a cleaner alternative to the manual reduce-into-a-map pattern that many codebases have been using for years. Browser support is wide as of 2025: Chrome 117+, Firefox 119+ and Safari 17.4+. For older targets, you can polyfill it via core-js.

The Array.map() method

Array.prototype.map() is a separate concept from the Map object. It’s a method on arrays that creates a new array by calling a callback on every element and collecting the return values. The original array is never modified. This non-mutating behavior is what makes JavaScript string interpolation and similar transformation pipelines clean to reason about.

const arr = [3, 4, 5, 6];

let modifiedArr = arr.map(function(element) {
    return element * 3;
});

console.log(modifiedArr); // [9, 12, 15, 18]

The callback receives up to three arguments: the current element, its index and the original array. Most of the time you only need the first.

Syntax

arr.map(callbackFn)
arr.map(callbackFn, thisArg)

callbackFn(element, index, array) — return the transformed value for each element. Whatever you return becomes the corresponding element in the new array.

map() over an array of objects

One of the most common uses of map() is reshaping arrays of objects: pulling out particular properties or restructuring each object.

let users = [
  {firstName : 'Susan', lastName: 'Steward'},
  {firstName : 'Daniel', lastName: 'Longbottom'},
  {firstName : 'Jacob', lastName: 'Black'}
];

let userFullnames = users.map(function(element) {
    return `${element.firstName} ${element.lastName}`;
});

console.log(userFullnames);
// ['Susan Steward', 'Daniel Longbottom', 'Jacob Black']

Common mistake: forgetting to return a value

If your callback doesn’t return anything, map() fills the position with undefined. This is one of the most frequent bugs with map().

const numbers = [1, 2, 3];

const broken = numbers.map(num => {
  num * 2; // forgot return
});

console.log(broken); // [undefined, undefined, undefined]

Fix it with an explicit return or use arrow function implicit return syntax:

const doubled = numbers.map(num => num * 2); // [2, 4, 6]

map() vs forEach() vs filter()

These three methods are often confused. The decision comes down to what you want back.

map() transforms every element and returns a new array of the same length. Use it when you need a parallel array of modified values.

forEach() runs a callback on every entry but returns undefined. Use it when you just want to produce side effects: logging, pushing to another array, updating DOM elements. If you find yourself calling map() and ignoring the returned array, switch to forEach().

filter() returns a new array containing only the entries where the callback returned truthy. Use it when you need a subset of the original.

const numbers = [1, 2, 3, 4, 5, 6];

// transform: double everything
const doubled = numbers.map(num => num * 2);
// [2, 4, 6, 8, 10, 12]

// side effect: just log
numbers.forEach(num => console.log(num));
// returns undefined

// subset: keep evens only
const evens = numbers.filter(num => num % 2 === 0);
// [2, 4, 6]

The JavaScript switch case is another good analogy here: each method handles a particular condition of what you’re trying to accomplish.

Chaining map(), filter() and reduce()

Because map() and filter() both return new arrays, you can chain them. A good rule of thumb: run filter() first to narrow the set, then run map() on the smaller result.

const numbers = [1, 2, 3, 4, 5, 6];

const result = numbers
  .filter(num => num % 2 === 0)  // [2, 4, 6]
  .map(num => num * 2);           // [4, 8, 12]

console.log(result); // [4, 8, 12]

You can extend the chain with reduce() to collapse the final array into a single value. reduce() must come last because it returns a non-array.

const total = numbers
  .filter(num => num % 2 === 0)
  .map(num => num * 2)
  .reduce((sum, num) => sum + num, 0);

console.log(total); // 24

This declarative pattern is more readable than nested loops and makes it obvious what each step does. If a chain grows long or involves side effects, it’s often cleaner to break it into named variables. Knowing how scope in JavaScript interacts with these closures becomes more relevant the longer the chain gets.

Using map() to render lists in React

In React, Array.map() is the standard way to render a list from an array of data. JSX is just JavaScript, so you can call map() directly inside your return statement.

const names = ['whale', 'squid', 'turtle', 'coral', 'starfish'];

const NamesList = () => (
  <div>
    <ul>{names.map(name => <li key={name}>{name}</li>)}</ul>
  </div>
);

The key prop here is required by React to track element identity across re-renders. Using map() to project data into JSX is one of the most practical patterns in React codebases.

WeakMap: the memory-efficient alternative

If you need Map-like key-value storage but don’t want to prevent garbage collection of your object keys, WeakMap is the right tool. It only allows object keys, has no size property and is not iterable. When the last external reference to a key object is gone, the WeakMap entry is garbage-collected automatically. No manual cleanup needed.

const cache = new WeakMap();

function process(obj) {
  if (!cache.has(obj)) {
    const result = { processed: true, id: obj.id };
    cache.set(obj, result);
  }
  return cache.get(obj);
}

This pattern works well for caching computed results against DOM elements or request objects without creating memory leaks. As the original article notes, if you’re curious about memory-based collections, WeakMap and WeakSet are the tools for lighter storage needs. WeakMap supports only set(), get(), delete() and has(). There is no keys(), values() or iteration, because the garbage collector can remove entries at any time.

Map vs Array: choosing the right structure

Map and arrays serve different purposes. An array is an ordered list where position (index) is the primary lookup mechanism. A Map is an unordered (in terms of key type) associative collection where a key of any type gives you direct access. For your JavaScript Array work like filtering or sorting, stick with arrays and their methods. When you need to associate metadata with objects, count occurrences or build a lookup table with non-string keys, reach for Map.

A practical pattern: use Array.map() to build a Map from an array.

const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
];

const userMap = new Map(users.map(user => [user.id, user]));

console.log(userMap.get(1)); // { id: 1, name: 'Alice' }

Now lookups by id are O(1) instead of O(n).

Key takeaways

  • Map preserves insertion order and accepts any key type: objects, functions and primitives.
  • Use set(), get(), has(), delete() and clear() to manage entries.
  • keys(), values() and entries() return iterators for partial traversal.
  • Array.map() creates a new array and never modifies the original.
  • Always return a value from your map() callback or you’ll get undefined in the result.
  • Chain filter() before map() to process fewer elements.
  • WeakMap allows garbage collection of entries whose keys lose all other references.

Frequently asked questions (FAQ)

What is map() in JavaScript?

map() in JavaScript refers to two things: the Map object (a keyed collection) and Array.prototype.map(), a method that transforms arrays by running a callback over every element and returning a new array.

What is the difference between Map and Object in JavaScript?

Map accepts any value as a key and guarantees insertion-order iteration. Object keys are strings or Symbols. Use Map when keys are non-strings or when you need predictable iteration order.

Does Array.map() change the original array?

No. Array.map() is non-mutating. It returns a new array with the transformed values and leaves the original array unchanged.

What is the difference between map() and forEach() in JavaScript?

map() returns a new transformed array. forEach() returns undefined and is used for side effects like logging or DOM updates. Use map() when you need the result array.

How do I iterate over a Map in JavaScript?

Use for...of with destructuring: for (const [key, value] of map), or call map.forEach((value, key) => {}). Note the reversed parameter order in forEach().

When should I use Map instead of an Object in JavaScript?

Use Map when your keys aren’t strings, when you need guaranteed iteration order, when you’re adding and removing entries frequently, or when you need the size property without manual counting.

What is WeakMap in JavaScript?

WeakMap is like Map but only accepts object keys and holds them weakly. When a key object loses all other references, its WeakMap entry is garbage-collected automatically. It has no size and is not iterable.

Final conclusion

Maps are one of the most underused data structures in JavaScript. Once you reach for them in situations where a plain object would have forced awkward string-keyed workarounds, the API feels immediately natural. If you want to go further, check out the JavaScript Array methods that pair well with Map. filter(), reduce() and Array.from() all integrate cleanly with Map-based data pipelines.

Aditya Gupta
Aditya Gupta
Articles: 512