How Lodash _.chain Enables Method Chaining
This article explains the internal mechanics of the
_.chain method in the Lodash JavaScript library. It
explores how _.chain encapsulates a target value inside a
dedicated wrapper object, preserves chaining state across sequential
method calls, intercepts function executions, and defers execution until
the wrapped value is explicitly extracted using the
.value() method.
The Lodash Wrapper Object
When you pass an argument to _.chain(value), Lodash does
not immediately transform the data. Instead, it creates an instance of
an internal constructor called LodashWrapper. This wrapper
encapsulates the original data as an internal property, typically stored
on the instance as __wrapped__.
By encapsulating the data within this wrapper, Lodash can expose its
entire utility suite as prototype methods on the newly created object.
Rather than calling standalone functions such as
_.map(array, fn), the wrapper allows direct invocation like
wrapperInstance.map(fn).
The __chain__ Flag
The defining characteristic of _.chain is the activation
of explicit chaining. When _.chain(value) constructs the
LodashWrapper instance, it sets an internal boolean
flag:
this.__chain__ = true;This flag dictates how subsequent method calls behave. Standard
Lodash wrapping via _(value) enables implicit chaining,
which automatically unwraps the result if a method returns a primitive
or a non-collection value (such as _.first or
_.sum). In contrast, setting __chain__ = true
ensures that every single method chained after _.chain()
returns another wrapped instance, regardless of what data type the
underlying operation produces.
Method Interception and Re-wrapping
Every utility method attached to the Lodash prototype is designed to
inspect the __chain__ property of the instance invoking it.
When a method like .filter(), .map(), or
.take() is called on a wrapped object:
- Extraction: The method retrieves the current value
stored in the
__wrapped__property. - Execution: The method runs the corresponding Lodash utility against the extracted value using the provided arguments.
- Chain Check: Lodash inspects whether
__chain__istrue. - Re-wrapping: Because
_.chainmarked the instance with__chain__ = true, the result of the operation is not returned as raw data. Instead, Lodash packages the result into a newLodashWrapperinstance with__chain__ = truemaintained.
Because each method call returns another LodashWrapper,
developers can string together multiple operations sequentially in a
readable pipeline.
Lazy Evaluation and Deferred Execution
In addition to state tracking, the wrapper coordinates Lodash’s lazy
evaluation engine, often referred to as shortcut fusion. When performing
sequences of array transformations (such as consecutive map
and filter operations), Lodash does not necessarily iterate
over the entire array for each step.
Instead, the wrapper queues the iteratees internally in an action
queue (__actions__). It combines compatible transformations
so that elements can be piped through the transformation sequence in a
single pass, minimizing unnecessary intermediate array allocations.
Unwrapping the Value
Because the __chain__ flag keeps operations wrapped
indefinitely, the chaining sequence cannot terminate automatically. To
retrieve the final computed JavaScript data, the consumer must invoke
.value() (or its alias, .toJSON() /
.valueOf()).
Calling .value() triggers the evaluation of any queued
actions against the __wrapped__ data, executes the shortcut
fusion pipeline, discards the wrapper object, and returns the plain
JavaScript value (such as an array, object, or primitive).