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:

  1. Calculates Length: It accesses the object's length property, converting it to an integer. If length is missing or 0, no operations occur.
  2. Identifies Swapping Pairs: It computes indices from 0 to Math.floor(length / 2) - 1 alongside their symmetric counterparts (length - 1 - index).
  3. Rearranges Keys: It swaps the values stored at the lower index and the upper index using standard internal get, set, and delete operations.
  4. 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: true

The 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: