Mapping over an object in JavaScript means creating a transformed version of its values. A normal Array.map() works only for arrays, so nested objects need a custom recursive function that checks whether each value is an array, object, or primitive value.
This pattern is useful when normalizing API responses, trimming strings, masking sensitive values, converting data types, or updating deeply nested configuration objects without mutating the original object.
Environment: Node.js v20.18.2. After each runnable snippet, the following paragraph states the expected console output (order and values).
Method 1: Recursively Map Every Primitive Value
This function keeps arrays as arrays, keeps objects as objects, and applies a callback only to primitive values.
function mapObject(value, fn) {
if (Array.isArray(value)) {
return value.map((item) => mapObject(item, fn));
}
if (value && typeof value === "object") {
return Object.fromEntries(
Object.entries(value).map(([key, child]) => [key, mapObject(child, fn)])
);
}
return fn(value);
}
const data = { name: "ana", meta: { active: true }, scores: [1, 2] };
const result = mapObject(data, (value) =>
typeof value === "string" ? value.toUpperCase() : value
);
console.log("recursive-map:", JSON.stringify(result));You should see one line logging recursive-map: {"name":"ANA","meta":{"active":true},"scores":[1,2]}.
The original structure is preserved while string values are transformed.
Method 2: Map Only Object Properties
If you only need shallow object mapping, use Object.entries() and Object.fromEntries().
const user = { first: "Ana", last: "Dev" };
const upper = Object.fromEntries(
Object.entries(user).map(([key, value]) => [key, value.toUpperCase()])
);
console.log(upper);You should see one line logging { first: 'ANA', last: 'DEV' }.
Use the recursive version only when the object can contain nested objects or arrays.
Method 3: Preserve the Original Object
The recursive map function above returns a new object. It does not mutate the input object.
const original = { user: { name: "ana" } };
const mapped = mapObject(original, (value) =>
typeof value === "string" ? value.toUpperCase() : value
);
console.log(original.user.name);
console.log(mapped.user.name);You should see 2 lines, in order: ana, ANA.
This makes the function safer for React state, Redux-style data, and other code where mutation can cause hard-to-find bugs.
Method 4: Handle null, Arrays, and Dates Carefully
In JavaScript, typeof null is "object", so always check value && typeof value === "object". Arrays also need their own branch because Object.entries() would convert array indexes into object keys.
If your data contains Date, Map, Set, or class instances, decide whether to preserve them, clone them, or transform them. A generic recursive object mapper should not blindly treat every object-like value as a plain object.
Common Questions About Mapping Objects in JavaScript
Can I use map() directly on an object?
No. map() is an array method. For objects, use Object.entries(), transform the entries, and rebuild the object with Object.fromEntries().
How do I map over nested objects?
Use recursion. Check arrays first, then plain objects, then apply the transform callback to primitive values.
Does recursive object mapping mutate the original object?
It depends on the implementation. The examples in this article return new objects and arrays, so the original input is preserved.
Summary
To recursively map an object in JavaScript, check whether each value is an array, object, or primitive value. Recursively map arrays and nested objects, then apply your transform function to the final values. This gives you a clean way to normalize or update deeply nested object data without mutating the original structure.
