How Lodash _.has Bypasses Inherited Object Getters
Lodash’s _.has method allows developers to safely check
for the existence of a property on an object without triggering side
effects from inherited getters. In JavaScript, checking or accessing
properties can inadvertently execute getter functions defined higher up
on the prototype chain. Lodash avoids this by restricting its lookup
exclusively to the target object's own properties and checking for
property existence at the internal descriptor level rather than
evaluating property values.
Property Evaluation vs. Property Existence
In standard JavaScript, evaluating a property using standard dot
notation or bracket notation (object.property) triggers the
internal [[Get]] operation. If that property is configured
with an accessor descriptor (a getter), JavaScript immediately executes
the corresponding function.
Furthermore, checking existence using the in operator
traverses the entire prototype chain. If a getter is defined on a
prototype—such as Object.prototype or a custom class
prototype—standard access patterns risk either evaluating inherited
logic or misidentifying inherited properties as direct properties of the
instance.
Reliance on
hasOwnProperty
Lodash's _.has functionally bypasses inherited object
getters by relying internally on
Object.prototype.hasOwnProperty.
Instead of resolving the property value, Lodash uses a guarded
reference to hasOwnProperty, typically invoked as:
Object.prototype.hasOwnProperty.call(object, key);This implementation achieves two distinct safeguards:
- Halts Prototype Chain Traversal:
hasOwnPropertychecks only the object's own internal property table. It never ascends the prototype chain. Any getter residing on an ancestor prototype is ignored entirely, ensuring inherited accessors cannot be triggered or evaluated. - Checks Slot Allocation Without Invoking
[[Get]]:hasOwnPropertyinspects the object's internal property descriptor records rather than reading the property. Because it only determines whether the property key exists on the instance itself, it checks existence without invoking accessor logic, even if the property itself is an "own" getter.
Distinction Between
_.has and _.hasIn
Lodash explicitly separates own-property checks from prototype-aware property checks:
_.has: Checks only direct properties usinghasOwnProperty. Inherited getters are never evaluated, checked, or traversed._.hasIn: Checks direct and inherited properties using theinoperator. While_.hasInchecks the prototype chain, theinoperator itself checks existence rather than evaluating the getter function, unlike direct member access (obj[prop]).
Nested Path Traversal
When resolving nested path strings or arrays (such as
'a.b.c'), _.has resolves intermediate segments
down to the parent object before executing the final check. For the
intermediate objects, Lodash reads the properties to traverse the path,
but the terminal property check is executed via
hasOwnProperty. Consequently, inherited getters at the
target property level are completely isolated from invocation.