How Lodash _.forOwn Iterates Over Own Properties
This article explores how the Lodash utility library implements
_.forOwn to restrict iteration strictly to an object's
directly attached enumerable keys. By examining the underlying
architectural layers—ranging from internal keys extraction and defensive
ownership checks to native reflection mechanisms—this overview
demonstrates how _.forOwn reliably isolates an object's own
properties while shielding execution from prototype chain inheritance
and property shadowing vulnerabilities.
The Underlying Iteration Pipeline
At a high level, _.forOwn serves as a specialized
wrapper around Lodash's generic iteration engine, baseFor.
While standard JavaScript for...in loops traverse both an
object’s own properties and its entire prototype chain,
_.forOwn prevents prototype traversal by pre-filtering
property keys or combining iteration with strict ownership checks.
In modern versions of Lodash, _.forOwn delegates
directly to an internal helper function, typically named
baseForOwn. This internal function coordinates iteration by
pairing a directional loop handler with an enumerable keys
retriever:
function baseForOwn(object, iteratee) {
return object && baseFor(object, iteratee, keys);
}By supplying its own internal keys retrieval function
rather than keysIn (which powers _.forIn),
Lodash forces the loop algorithm to operate exclusively on direct
keys.
Delegation to Native
Object.keys
The primary layer of security and performance in
_.forOwn is its dependency on Object.keys (or
its internal equivalent, baseKeys).
In ECMAScript environments, Object.keys() is defined by
the runtime specification to return an array of an object's own
enumerable string-keyed properties. By collecting these keys prior to
iteration, Lodash delegates the boundary enforcement directly to the
JavaScript engine's C++ layer. Inherited properties from
Object.prototype or custom constructor prototypes are
eliminated from the iteration target set before the user-supplied
iteratee function is ever invoked.
Defensive Ownership Checks
When handling legacy runtimes or complex objects where prototype traps might exist, Lodash guarantees encapsulation by shielding against shadowed or severed methods.
A common failure point in native JavaScript occurs when attempting to
call object.hasOwnProperty(key) directly:
- The target object may have been initialized via
Object.create(null), leaving it without access toObject.prototype. - The property name
hasOwnPropertymay be shadowed or overwritten on the object itself (e.g.,{ hasOwnProperty: false }).
Lodash circumvents this by referencing the uncorrupted prototype method internally:
const hasOwnProperty = Object.prototype.hasOwnProperty;
function hasPath(object, key) {
return object != null && hasOwnProperty.call(object, key);
}By leveraging Function.prototype.call with the root
Object.prototype.hasOwnProperty, Lodash safely verifies
whether a property exists directly on the target instance, completely
bypassing the instance's own prototype chain.
Strict Enumerable Filtering
Not all own properties should be traversed during functional
iteration. JavaScript allows properties to be marked as non-enumerable
via Object.defineProperty.
_.forOwn strictly adheres to enumerability
specifications. In environments requiring fallback mechanisms for
complex types (such as arguments objects, typed arrays, or
prototype objects with non-standard descriptors), Lodash uses helper
utilities like isPrototype and custom index validators to
ignore non-enumerable internal attributes (like length on
functions or constructor references on prototypes).
Mitigation of Prototype Pollution
By encapsulating property discovery within safe retrieval boundaries,
_.forOwn acts as a guard against prototype pollution
attacks.
When external payloads inject malicious properties into an
application's shared prototypes (such as Object.prototype),
standard for...in loops will process those unexpected keys.
Because _.forOwn anchors its key list strictly to the
immediate object using Object.keys and safe
hasOwnProperty checks, injected prototype properties are
systematically ignored. This guarantees that iteration logic processes
only data explicitly set on the target instance itself.