Question

How to Map Over Object Properties in JavaScript

javascriptnode.jsfunctional-programmingmap-function

Question

I have a JavaScript object:

const myObject = { a: 1, b: 2, c: 3 };

I want a native method similar to Array.prototype.map() that I could use like this:

const newObject = myObject.map(function (value, key) {
  return value * value;
});

// newObject should become: { a: 1, b: 4, c: 9 }

Does JavaScript provide a built-in map() function for plain objects? I am using Node.js, so browser compatibility is not a concern.

Short Answer

By the end of this page, you will understand why plain JavaScript objects do not have a built-in map() method, and how developers typically achieve the same result using Object.keys(), Object.entries(), Object.fromEntries(), loops, or small helper functions. You will also learn when to use an object versus an array for transformations.

Concept

Plain JavaScript objects and arrays are different data structures.

  • Arrays are ordered collections and come with array methods like map(), filter(), and reduce().
  • Objects are key-value collections and do not have a built-in map() method.

So the direct answer is: No, JavaScript does not provide a native map() method for plain objects.

However, you can still "map over" an object's properties by converting the object into something iterable, transforming it, and then turning it back into an object.

A common modern pattern is:

  1. Get the object's entries with Object.entries(obj)
  2. Use array methods like map()
  3. Rebuild an object with Object.fromEntries()

Example:

const myObject = { a: 1, b: 2, c: 3 };

const newObject = Object.fromEntries(
  Object.entries(myObject).map(([key, value]) => [key, value * value])
);

console.log(newObject); // { a: 1, b: 4, c: 9 }

This matters in real programming because object transformation is common when:

  • formatting API responses
  • converting configuration values
  • normalizing data
  • applying validation or cleanup logic
  • renaming or recalculating fields

Understanding this pattern helps you work cleanly with JavaScript data structures instead of trying to force array methods onto objects.

Mental Model

Think of an array as a row of numbered boxes:

  • box 0
  • box 1
  • box 2

Because arrays are ordered, JavaScript gives them tools like map() to process each box in sequence.

Think of an object as a set of labeled drawers:

  • drawer a
  • drawer b
  • drawer c

Objects are organized by keys, not by numeric positions. Since they are not arrays, they do not automatically get array methods like map().

So when you want to "map an object," you usually:

  1. open all the labeled drawers (Object.entries())
  2. transform each drawer's contents (map())
  3. rebuild the cabinet (Object.fromEntries())

That is the core idea.

Take Quiz

Syntax and Examples

The most common ways to transform object values are shown below.

1. Using Object.entries() and Object.fromEntries()

const myObject = { a: 1, b: 2, c: 3 };

const squared = Object.fromEntries(
  Object.entries(myObject).map(([key, value]) => [key, value * value])
);

console.log(squared); // { a: 1, b: 4, c: 9 }

How it works

  • Object.entries(myObject) returns:
[['a', 1], ['b', 2], ['c', 3]]
  • Then .map() transforms each [key, value]
  • Object.fromEntries() builds a new object from the transformed pairs

2. Using Object.keys()

const myObject = { a: 1, b: 2, c: 3 };
const result = {};

Object.keys(myObject).forEach((key) => {
  result[key] = myObject[key] * myObject[key];
});

console.log(result); // { a: 1, b: 4, c: 9 }

This is slightly more manual, but very readable.

3. Creating a reusable helper

function mapObject(obj, callback) {
  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => [key, callback(value, key)])
  );
}

const myObject = { a: 1, b: 2, c: 3 };

const newObject = mapObject(myObject, (value, key) => value * value);

console.log(newObject); // { a: 1, b: 4, c: 9 }

This gives you a function that feels similar to array map().

4. Using a for...of loop

const myObject = { a: 1, b: 2, c: 3 };
const newObject = {};

for (const [key, value] of Object.entries(myObject)) {
  newObject[key] = value * value;
}

console.log(newObject); // { a: 1, b: 4, c: 9 }

This is a good option when you want simple, explicit code.

Step by Step Execution

Consider this example:

const myObject = { a: 1, b: 2, c: 3 };

const result = Object.fromEntries(
  Object.entries(myObject).map(([key, value]) => [key, value * 2])
);

console.log(result);

Here is what happens step by step.

Step 1: Start with the original object

{ a: 1, b: 2, c: 3 }

Step 2: Convert the object into entries

Object.entries(myObject)

Result:

[['a', 1], ['b', 2], ['c', 3]]

Now the data is in an array, so array methods like map() can be used.

Step 3: Map each entry

.map(([key, value]) => [key, value * 2])

Each entry is transformed:

  • ['a', 1] becomes ['a', 2]
  • ['b', 2] becomes ['b', 4]
  • ['c', 3] becomes ['c', 6]

Now we have:

[['a', 2], ['b', 4], ['c', 6]]

Step 4: Convert the mapped entries back into an object

Object.fromEntries(...)

Result:

{ a: 2, b: 4, c: 6 }

Step 5: Print the final object

console.log(result);

Output:

{ a: 2, b: 4, c: 6 }

Real World Use Cases

Object mapping is useful whenever you need to transform values while keeping the same keys.

Common examples

1. Formatting API response data

const prices = { apple: 1.2, banana: 0.8 };

const formatted = Object.fromEntries(
  Object.entries(prices).map(([key, value]) => [key, `$${value.toFixed(2)}`])
);

console.log(formatted); // { apple: '$1.20', banana: '$0.80' }

2. Converting configuration values

const envConfig = { port: '3000', debug: 'true' };

const parsed = {
  port: Number(envConfig.port),
  debug: envConfig.debug === 'true'
};

Or with a helper when rules are consistent.

3. Normalizing imported data

const scores = { alice: 10, bob: 20 };

const normalized = Object.fromEntries(
  Object.entries(scores).map(([name, score]) => [name, score / 10])
);

4. Cleaning user input

const input = { firstName: ' Alice ', city: ' London ' };

const cleaned = Object.fromEntries(
  Object.entries(input).map(([key, value]) => [key, value.trim()])
);

5. Preparing data before saving to a database

const flags = { emailVerified: 1, isAdmin: 0 };

const booleans = Object.fromEntries(
  Object.entries(flags).map(([key, value]) => [key, Boolean(value)])
);
Take Quiz

Real Codebase Usage

In real projects, developers usually do not try to add map() directly to all objects. Instead, they use one of these patterns.

1. Small utility function

A reusable helper keeps code clean.

function mapObjectValues(obj, transform) {
  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => [key, transform(value, key)])
  );
}

This is common in service layers, data formatting utilities, and validation modules.

2. Guard clauses before transformation

Real code often validates input first.

function mapObjectValues(obj, transform) {
  if (obj === null || typeof obj !== 'object' || Array.isArray(obj)) {
    throw new TypeError('Expected a plain object');
  }

  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => [key, transform(value, key)])
  );
}

This avoids unexpected errors.

3. Early returns for empty objects

function doubleValues(obj) {
  if (Object.keys(obj).length === 0) {
    return {};
  }

  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => [key, value * 2])
  );
}

4. Combining map with filtering

Sometimes developers first remove unwanted keys, then transform.

const settings = { theme: 'dark', cache: null, language: 'en' };

const cleaned = Object.fromEntries(
  Object.entries(settings)
    .filter(([, value]) => value !== null)
    .map(([key, value]) => [key, String(value)])
);

5. Error handling during transformation

function safeParseNumbers(obj) {
  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => {
      const num = Number(value);
      if (Number.isNaN(num)) {
        throw new Error(`Invalid number for key: ${key}`);
      }
      return [key, num];
    })
  );
}

These are the kinds of patterns you see in production code.

Common Mistakes

1. Trying to call .map() directly on an object

This does not work:

const obj = { a: 1, b: 2 };
obj.map((value) => value * 2);

Why it fails:

  • plain objects do not have a map() method

Use this instead:

const result = Object.fromEntries(
  Object.entries(obj).map(([key, value]) => [key, value * 2])
);

2. Using Object.keys() but forgetting to build a new object

Broken idea:

const obj = { a: 1, b: 2 };
const result = Object.keys(obj).map((key) => obj[key] * 2);

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

This returns an array, not an object.

If you want an object, rebuild it:

const result = Object.fromEntries(
  Object.keys(obj).map((key) => [key, obj[key] * 2])
);

3. Mutating the original object by accident

const obj = { a: 1, b: 2 };

Object.keys(obj).forEach((key) => {
  obj[key] = obj[key] * 2;
});

console.log(obj); // original object changed

If you want a new object, assign into a separate object.

4. Confusing arrays and objects

const data = { 0: 'a', 1: 'b' };

This may look array-like, but it is still an object. It does not get array methods.

5. Ignoring inherited properties when using for...in

for (const key in obj) {
  // may include inherited properties
}

Safer for most transformations:

  • Object.keys(obj)
  • Object.entries(obj)
  • Object.hasOwn(obj, key) when needed

6. Forgetting that keys are strings

Object keys are typically strings, even if they look numeric.

const obj = { 1: 'one', 2: 'two' };
console.log(Object.keys(obj)); // ['1', '2']

Comparisons

ApproachWorks onReturnsBest forExample
Array.prototype.map()ArraysNew arrayOrdered lists[1, 2, 3].map(x => x * 2)
Object.keys() + loopObjectsWhatever you buildSimple object transformationsbuild result manually
Object.entries() + map() + Object.fromEntries()ObjectsNew objectClean value/key transformationtransform key-value pairs
for...inObjectsWhatever you buildOlder or manual iterationmust check own properties
reduce() on entriesArrays or converted object entriesAny structureFlexible accumulationadvanced but powerful

Object.keys() vs Object.entries()

MethodOutputBest when
Object.keys(obj)Array of keysYou only need keys
Object.values(obj)Array of valuesYou only need values
Object.entries(obj)Array of [key, value] pairsYou need both key and value

Object vs Array

FeatureObjectArray
StructureKey-value pairsOrdered list
Has native map()NoYes
Good forNamed fields, dictionariesSequences of items
Common accessobj.name or obj['name']arr[0]
Take Quiz

Cheat Sheet

// No native object.map() exists for plain objects

Common pattern

const result = Object.fromEntries(
  Object.entries(obj).map(([key, value]) => [key, transform(value, key)])
);

Reusable helper

function mapObject(obj, fn) {
  return Object.fromEntries(
    Object.entries(obj).map(([key, value]) => [key, fn(value, key)])
  );
}

Alternatives

Using Object.keys()

const result = {};
Object.keys(obj).forEach((key) => {
  result[key] = fn(obj[key], key);
});

Using for...of

const result = {};
for (const [key, value] of Object.entries(obj)) {
  result[key] = fn(value, key);
}

Important rules

  • Plain objects do not have .map()
  • Object.entries(obj) gives [[key, value], ...]
  • Object.fromEntries(entries) turns entries back into an object
  • Object.keys(obj).map(...) returns an array unless you rebuild an object
  • Use arrays when you need array methods directly

Edge cases

  • null is not a valid object to map over
  • Arrays are objects, but should usually be handled with array methods instead
  • for...in may include inherited properties
  • Object keys are usually strings

FAQ

Is there a native map() for JavaScript objects?

No. Plain objects do not have a built-in map() method.

What is the modern way to map over an object in JavaScript?

The most common modern approach is:

Object.fromEntries(
  Object.entries(obj).map(([key, value]) => [key, transform(value, key)])
)

Can I use Object.keys() instead of Object.entries()?

Yes. Object.keys() works well if you only need the keys and can access values with obj[key].

Why does Object.keys(obj).map(...) return an array?

Because Object.keys(obj) returns an array, and array map() always returns a new array.

Should I add map() to Object.prototype?

Usually no. Modifying built-in prototypes can cause confusion and bugs in real projects.

Is for...in a good way to map an object?

It can work, but you must be careful about inherited properties. Object.keys() or Object.entries() are usually safer.

What if I only want to transform values and keep the same keys?

Use Object.entries() with Object.fromEntries(), or a helper function that wraps that pattern.

Take Quiz

Mini Project

Description

Build a small utility that transforms the values of a settings object while keeping the same keys. This demonstrates the standard JavaScript pattern for object mapping and mirrors how developers normalize configuration or API data in real projects.

Goal

Create a reusable mapObjectValues() function and use it to transform an object's values into a new object.

Requirements

  • Create a function named mapObjectValues that accepts an object and a callback.
  • Return a new object instead of mutating the original one.
  • Pass both value and key to the callback.
  • Use the function to transform a sample object of numeric values.
  • Print both the original object and the transformed object.
Take Quiz

Keep learning

Related questions

View more