Lodash forOwnRight and Dynamic Property Deletion
When using Lodash's _.forOwnRight, deleting an object's
properties dynamically during iteration does not alter the predefined
iteration queue. Because Lodash captures the object's own enumerable
keys upfront, the internal evaluation scope retains the full list of
property names, resulting in the iteratee executing for deleted
properties with an undefined value.
Key Pre-Collection and Snapshotting
Under the hood, _.forOwnRight delegates iteration to
internal methods that extract the object's own enumerable string keys
before iteration begins. This key extraction relies on Lodash's
keys utility, which generates a static array snapshot
equivalent to calling Object.keys(object).
Because this array of property names is constructed prior to the
first iteration, the traversal list is fixed in memory. The evaluation
scope of the loop maintains an index pointer that starts at
keys.length - 1 and decrements toward 0.
The Effect of Dynamic Deletion
When a property is deleted using the delete operator
inside the iteratee callback, two scenarios occur depending on the
iteration order:
- Deleting an Already Processed Property: If the iteratee deletes a property that appeared earlier in the reverse traversal (a property located at a higher index in the internal keys array), the deletion has zero impact on the remaining loop cycles.
- Deleting an Upcoming Property: If the iteratee deletes a property scheduled for a future step (a property located at a lower index in the keys array), the key remains in the pre-collected key array.
When the decrementing pointer reaches the deleted key, Lodash still invokes the iteratee function. During the invocation:
- The first argument (
value) resolves toundefinedvia runtime property access (object[key]). - The second argument (
key) remains the string identifier of the deleted property. - The third argument (
collection) passes the mutated object reference.
Evaluation Scope and Execution Context
The evaluation scope of the running loop is bound to the static keys
array and the loop index, not to the live state of the object's property
descriptor table. Unlike native for...in loops, which
dynamically query the object's prototype chain and property status on
each tick and typically skip deleted properties,
_.forOwnRight operates strictly over its internal array
snapshot.
Consequently, the iteratee must explicitly guard against
undefined values or verify property presence using
Object.prototype.hasOwnProperty.call(object, key) if
properties are pruned dynamically during reverse iteration.