Lodash reduceRight Object vs Array Traversal
Lodash’s _.reduceRight method executes a reducer
function over a collection from right to left, but its traversal
mechanism differs fundamentally between arrays and plain objects. While
arrays are stepped through sequentially from the highest numeric index
down to zero, objects are evaluated by first determining their
enumerable own keys and iterating through that key set in reverse order.
Understanding this distinction is critical for predicting accumulator
values, handling non-sequential property orders, and avoiding subtle
bugs during data transformations.
Array Traversal: Index-Based Decrementing
When supplied with an array, _.reduceRight relies on the
collection's indexed structure:
- Order of Execution: Iteration begins at index
length - 1and decrements sequentially down to index0. - Callback Arguments: In each step, the iteratee
receives
(accumulator, value, index, collection). - Performance: Because arrays are indexed sequentially, the operation runs with minimal overhead, directly accessing values via their integer indices in descending order.
For example, given [1, 2, 3], the iteratee processes the
element 3 (index 2), then 2
(index 1), and finally 1 (index
0).
Object Traversal: Key Extraction and Reversal
JavaScript objects do not have native backward iteration, nor are
their properties stored in a strictly linear manner. When
_.reduceRight receives an object, it handles traversal
through a multi-step process:
- Key Resolution: Lodash retrieves the object's own
enumerable properties, adhering to the ECMAScript specification for
property order:
- Non-negative integer-like keys are sorted in ascending numerical order.
- String keys are listed in the order they were inserted.
- Symbol keys are handled separately (or omitted by default object key iterators).
- Reverse Iteration: Lodash iterates through this resolved list of property keys from the last key to the first.
- Callback Arguments: The iteratee receives
(accumulator, value, key, collection).
Because keys must be gathered before iteration begins, reducing an object carries the memory and computational overhead of creating this intermediate key list.
Key Traversal Differences
| Feature | Array Traversal | Object Traversal |
|---|---|---|
| Iteration Mechanism | Decrementing integer counter | Reverse iteration over resolved key list |
| Position Identifier | Numeric index (0 to
n - 1) |
String property name |
| Order Determinism | Strictly strictly reverse index order | Dependent on ECMAScript key sorting rules |
| Intermediate Allocation | No key array allocation required | Allocates a list of property keys first |
The Impact of Numeric Object Keys
A common pitfall occurs when objects use numeric strings as keys.
Because ECMAScript sorts integer keys in ascending order prior to
standard string keys, _.reduceRight will always visit the
highest integer key first among the integer keys, regardless of
insertion order:
const obj = {
'b': 'second_string',
'1': 'first_number',
'2': 'second_number',
'a': 'first_string'
};In this case, Lodash resolves the keys in the order
['1', '2', 'b', 'a']. Consequently,
_.reduceRight traverses them in reverse: 'a',
then 'b', then '2', and finally
'1'.
Arrays, by contrast, follow strict, contiguous numerical boundaries where elements are always consumed strictly from right to left as defined by array positioning.