How Lodash cloneWith Handles Prototype Properties
This article examines how Lodash’s _.cloneWith method
evaluates its customizer function with respect to object
prototypes and inherited properties. It explains how Lodash isolates own
properties from the prototype chain during cloning, clarifies why
inherited prototype properties are never passed directly to the
customizer, and demonstrates how developers can still customize
prototype behavior during cloning operations.
Own Properties vs. Inherited Prototype Properties
When _.cloneWith processes an object, it restricts
property copying strictly to the object's own enumerable
properties. Under the hood, Lodash utilizes internal mechanisms
(equivalent to Object.keys or Reflect.ownKeys)
rather than a for...in loop that traverses up the prototype
chain.
Because inherited properties residing on the prototype chain are not
considered own properties, the customizer function is never
invoked for individual prototype properties. The customizer arguments
(value, key, object, stack) will only receive values that
exist directly on the target instance itself.
Prototype Preservation in the Default Cloning Path
If the customizer returns undefined,
_.cloneWith falls back to Lodash's internal
baseClone routine. For objects with custom prototypes (such
as instances of classes or constructor functions):
- Instantiation: Lodash initializes the cloned target
by preserving the prototype, typically via
Object.create(Object.getPrototypeOf(object))or by initializing an instance via its original constructor. - Property Assignment: It then assigns the object's own properties to this newly initialized clone.
Because prototype properties remain attached to the prototype object rather than copied onto the instance, their behavior, getters, setters, and inherited methods remain shared through prototype delegation.
How the Customizer Evaluates the Root Object
While the customizer does not fire for individual
prototype properties, it is evaluated for the root
object itself. This is where prototype handling can be
explicitly altered.
When customizer(value) is called on the object:
- The
keyandobjectparameters areundefinedfor the root invocation. - If you return a new object with a custom prototype (for instance,
via
Object.assign(Object.create(newPrototype), value)), Lodash uses your returned instance directly and halts further cloning for that node. - If you return
undefined, Lodash continues with its standard prototype-preserving shallow clone.
Behavior in Deep
Cloning (_.cloneDeepWith)
It is also important to contrast this with
_.cloneDeepWith. Even during a recursive deep clone, the
customizer descends solely into nested own properties.
Properties defined on an object’s prototype or
__proto__ remain untouched by the customizer throughout the
entire depth of the traversal, ensuring prototype chains are not
accidentally flattened into own properties on clones.