Lodash assignIn and Prototype Chain Inheritance
This article examines the exact mechanics of Lodash’s
_.assignIn (also known as _.extend) when
transferring properties from deeply nested prototype chains to a target
object. It details the specific categories of properties that are
copied—such as enumerable string-keyed properties—as well as those that
are excluded, including Symbols, non-enumerable descriptors, and
uninvoked accessors.
Enumerable String-Keyed Properties
_.assignIn iterates over both own and inherited
properties of source objects. Across a deep prototype chain, it
transfers only enumerable, string-keyed properties.
Under the hood, _.assignIn uses Lodash's internal
keysIn operation, which mimics the behavior of a standard
JavaScript for...in loop. Any property defined along the
prototype chain that has its enumerable attribute set to
true is extracted and copied to the target object as an own
property.
Excluded Properties
When traversing prototype chains, _.assignIn
deliberately ignores several types of properties:
- Non-Enumerable Properties: Built-in methods on
Object.prototype(such astoString,valueOf, andhasOwnProperty) and custom methods or fields defined viaObject.definePropertywithenumerable: falseare skipped. - Symbol-Keyed Properties: Inherited or own
properties keyed by ES6 Symbols are not transferred. Lodash restricts
_.assignInstrictly to string keys. - Prototype References: The actual prototype linkages
(
__proto__) are not copied. The target object does not adopt the prototype chain of the source; instead, the inherited properties are flattened into own properties on the target.
Prototype Shadowing and Resolution Order
When the same property name exists at multiple levels of a deep
prototype chain, _.assignIn honors JavaScript's standard
prototype shadowing rules:
- Properties found closest to the source instance take precedence over properties higher up in the chain.
- If an instance defines an own property
x, and its prototype also definesx, the value on the instance is the one assigned to the target. - If multiple source objects are supplied to
_.assignIn(target, source1, source2), subsequent sources overwrite properties set by earlier sources.
Value Evaluation and Accessors
_.assignIn performs an assignment ([[Set]])
rather than a property descriptor definition
([[DefineOwnProperty]]):
- Getters: If an inherited property is configured as
an accessor descriptor (a getter),
_.assignIninvokes the getter during iteration and assigns the resulting return value to the target as a plain data property. The getter function itself is not copied. - Setters: If the target object has a setter for a matching property name, the transferred value will trigger that setter on the target.