How Lodash _.reverse Handles Array-Like Objects
When _.reverse is called on an array-like object that
lacks a native reverse method, Lodash successfully reverses
the object's indexed properties in place and returns the mutated object.
This behavior occurs because Lodash internally delegates the operation
to JavaScript's generic Array.prototype.reverse via
Function.prototype.call, which relies entirely on property
indices and the object's length property rather than
checking for an object-level reverse method.
Internal Delegation to Array.prototype.reverse
Lodash defines _.reverse by caching a reference to
Array.prototype.reverse:
var nativeReverse = Array.prototype.reverse;
function reverse(array) {
return array == null ? array : nativeReverse.call(array);
}Because nativeReverse.call(array) explicitly sets the
this context of Array.prototype.reverse to the
provided array-like object, the method does not search for or invoke a
reverse property on the input itself.
How Generic Reversal Works on Array-Like Objects
The ECMAScript specification designs
Array.prototype.reverse as intentionally generic. For any
object passed as this, the engine executes the following
algorithm:
- Calculates Length: It accesses the object's
lengthproperty, converting it to an integer. Iflengthis missing or0, no operations occur. - Identifies Swapping Pairs: It computes indices from
0toMath.floor(length / 2) - 1alongside their symmetric counterparts (length - 1 - index). - Rearranges Keys: It swaps the values stored at the lower index and the upper index using standard internal get, set, and delete operations.
- Returns the Object: The mutated target object is returned directly.
Practical Example
Consider a custom array-like object with sequential keys and a
length property:
const arrayLike = {
0: 'alpha',
1: 'beta',
2: 'gamma',
length: 3
};
const result = _.reverse(arrayLike);
console.log(result);
// Output: { '0': 'gamma', '1': 'beta', '2': 'alpha', length: 3 }
console.log(result === arrayLike);
// Output: trueThe operation runs cleanly on structures like DOM
NodeList instances, function arguments
objects, or plain JavaScript objects with an explicit integer
length.
Exceptions and Edge Cases
While the lack of an existing .reverse() method does not
prevent execution, certain constraints apply:
- Object Mutability: If the array-like object is
frozen (
Object.freeze()) or sealed with read-only index properties, aTypeErrorwill be thrown when the algorithm attempts to overwrite keys. - Missing or Invalid
length: If the object does not have a numericlengthproperty (or iflength <= 1), Lodash leaves the properties unchanged and returns the object as-is. - Sparse Objects: If indexed properties are missing
within the range specified by
length, the algorithm retains the holes, swapping property existence states accordingly.