How Lodash invokeMap Works Without Mutating Objects

Lodash's _.invokeMap allows developers to call a specific method on each element in a collection, returning the results in a newly constructed array. This article breaks down the internal mechanics of _.invokeMap, explaining how it executes method calls natively via standard JavaScript invocation patterns, manages duplicate object references without side effects, and guarantees that the underlying collection and its references remain structurally unmutated.

The Internal Architecture of _.invokeMap

At its core, _.invokeMap delegates collection processing through internal helper functions, primarily baseEach and baseInvoke. When invoked, the function does not alter the incoming collection. Instead, it inspects the collection type and initializes a brand-new array to store the execution results:

var result = isArrayLike(collection) ? Array(collection.length) : [];

By pre-allocating or instantiating an entirely distinct array for the return values, Lodash ensures that the structure of the input collection is isolated from the start.

Native Dispatch via Function Application

To execute the target method natively, _.invokeMap determines whether the method identifier is a direct function reference or a path string.

  1. Direct Function: If the path parameter is a function, Lodash invokes it directly against the current element using standard JavaScript function binding:
    path.apply(value, args);
  2. Path String: If a property path is supplied (such as 'toUpperCase' or a deep path like 'nested.method'), the internal utility baseInvoke navigates the object’s property chain natively to resolve the function reference. Once resolved, it calls the method in the context of the parent object using func.apply(parent, args).

Because Lodash relies on native Function.prototype.apply, the method execution operates within the standard ECMAScript runtime dispatch mechanism. Lodash creates no wrappers, proxies, or synthetic execution contexts around the target object.

Handling Identically Referenced Objects

A common concern in functional operations is how an engine behaves when multiple indices point to the exact same object reference:

const shared = { getValue: () => 42 };
const list = [shared, shared];

When _.invokeMap(list, 'getValue') executes, Lodash processes each element iteratively using an internal counter:

  1. Lodash passes the reference at index 0 (shared) to the invocation pipeline.
  2. The method is called natively, and the returned value is assigned to the output container: result[0] = 42.
  3. The iteration proceeds to index 1, reading the identical reference (shared).
  4. The method is called again, and the return value is assigned to result[1] = 42.

Because _.invokeMap writes outputs strictly to the newly allocated result array indices rather than setting properties on the iterated items, identical references cannot cross-contaminate one another through Lodash's internal logic.

Preventing Mutation

Lodash guarantees non-mutation through three specific structural constraints: