Lodash Prototype Reverse and Array Mutation

This article examines how the Lodash JavaScript library handles sequence reversals, detailing the fundamental structural mutation caused by native prototype.reverse during chained and mapped transformations. It covers the internal differences between eager mutation using native Array.prototype.reverse and deferred traversal via lazy evaluation wrappers, illustrating how mapped data structures are reorganized in memory.

The Underlying Mutation: In-Place Index Reversal

In standard JavaScript and Lodash execution pipelines, the fundamental structural mutation that reorganizes mapped values is in-place buffer mutation executed via Array.prototype.reverse. When invoked on a standard Lodash sequence wrapper (LodashWrapper), Lodash delegates the operation directly to native array reversal mechanisms rather than creating an immutable clone.

Native Array.prototype.reverse mutates the target array directly in memory by swapping indices from the outer boundaries inward toward the center:

  1. The element at index i is swapped with the element at index length - 1 - i.
  2. The references stored at each slot are preserved, but their positional keys are transposed.
  3. The underlying array reference (this.__wrapped__) is modified permanently in place.

When operations such as .map() produce an intermediate mapped collection in an eager sequence, calling .reverse() fundamentally rearranges those mapped elements by mutating that intermediate array instance rather than allocating a newly indexed container.

Eager Chains vs. Lazy Evaluation

Lodash employs two distinct structural wrappers depending on how methods are chained: LodashWrapper (eager/shortcut-capable chaining) and LazyWrapper (true deferred evaluation).

1. Eager Chains (LodashWrapper)

In standard chaining (e.g., _(array).map(fn).reverse().value()), if the chain cannot be lazily compiled, Lodash executes operations sequentially. The mapping pass yields a new array of transformed values, and .reverse() applies Array.prototype.reverse natively to that collection. The mutation directly targets the physical array pointer held inside the wrapper instance.

2. Deferred Direction Flipping (LazyWrapper)

When Lodash activates lazy evaluation (often triggered when chaining arrays of length greater than 200 with methods like filter, map, and take), calling .reverse() avoids immediate in-place mutation.

Instead of mutating memory positions, LazyWrapper.prototype.reverse performs a structural configuration change on the wrapper instance itself:

When the chain is resolved via .value(), iteration begins from the tail index instead of the head index. However, if unshift/splice or strict native calls force synchronization, Lodash falls back to flushing pending actions through Array.prototype.reverse.

Structural Effects on Deep and Nested Data

While prototype.reverse fundamentally mutates the index positions of the array structure, its effect on deeper nested structures depends on reference handling: