Does Lodash mapKeys Mutate Original Objects?

This article examines the structural behavior of Lodash’s _.mapKeys method and its impact on source object references during execution. It explains whether structural mutations occur on the original reference, how key transformations are instantiated, and how value references are handled across the iteration lifecycle.

Structural Mutation Behavior of _.mapKeys

When _.mapKeys executes, it applies zero structural mutations to the original object reference.

In JavaScript and Lodash design paradigms, _.mapKeys is an immutable transformation function. It does not delete, rename, reorder, or add properties to the input object passed as its first argument. The original object's prototype, property descriptors, and own enumerable properties remain completely untouched throughout and after the iteration loop.

How _.mapKeys Executes Internally

To understand why no structural mutation occurs, it helps to examine how the iteration operates:

  1. Initialization of a New Object: Before iterating, Lodash initializes a completely new, empty object target ({}).
  2. Iteration Over Keys: Lodash traverses the own enumerable string-keyed properties of the source object using an internal iteration utility (similar to baseForOwn).
  3. Iteratee Invocation: For each property, the provided iteratee callback is invoked with three arguments: (value, key, object).
  4. Assignment to the Target: The return value of the iteratee is cast to a string and assigned as a key on the newly created object, with the corresponding value from the original property assigned to that key.
  5. Return Value: Once iteration completes, the newly constructed object is returned. The original reference is never targeted for property assignment.
const original = { a: 1, b: 2 };
const transformed = _.mapKeys(original, (value, key) => key + '_new');

console.log(original);    // { a: 1, b: 2 } (completely unchanged)
console.log(transformed); // { a_new: 1, b_new: 2 }
console.log(original === transformed); // false

Shallow Reference Copying of Property Values

While the structure (the keys and the object wrapper) of the original object is preserved without mutation, _.mapKeys performs a shallow copy of the property values:

Because values are copied by reference, both the original object and the newly generated object point to the exact same memory locations for nested structures. Modifying a nested object via either reference will reflect in both places:

const original = { user: { name: 'Alice' } };
const mapped = _.mapKeys(original, (value, key) => key.toUpperCase());

// Structural keys differ:
// original has 'user', mapped has 'USER'

// Modifying nested property via the new object:
mapped.USER.name = 'Bob';

// The nested mutation reflects in the original:
console.log(original.user.name); // 'Bob'

Potential Mutations via Custom Iteratee Callbacks

Although _.mapKeys itself does not perform structural mutations, the iteratee function receives the original object as its third parameter: iteratee(value, key, object).

If a developer explicitly writes logic inside the iteratee that mutates the received object argument (e.g., delete object[key] or object[key] = null), structural mutations will occur as a direct result of user-defined side effects, not from the mechanics of Lodash itself.