How Lodash Distinguishes Array-Like Objects

In the Lodash JavaScript library, _.forEach determines how to iterate over an item by evaluating structural characteristics rather than inspecting constructor names or class prototypes. Through an internal duck-typing check called isArrayLike, Lodash checks for the existence of a valid numeric length property; if present and valid, it runs an index-based loop (0 to length - 1), and if absent, it falls back to iterating over the object's enumerable keys.

The Internal Mechanism: isArrayLike

When _.forEach (or its internal implementation baseEach) receives a collection, it branches execution based on the isArrayLike utility function. The check follows this logic:

function isArrayLike(value) {
  return value != null && typeof value !== 'function' && isLength(value.length);
}

This single evaluation distinguishes standard arrays, strings, DOM NodeLists, and the arguments object from standard objects and class instances.

The Role of isLength

For an object to qualify as array-like, its length property must pass the isLength validator:

const MAX_SAFE_INTEGER = 9007199254740991;

function isLength(value) {
  return typeof value === 'number' &&
    value > -1 &&
    value % 1 === 0 &&
    value <= MAX_SAFE_INTEGER;
}

The property must be a non-negative, safe integer.

Handling Standard Class Instances

A standard class instance or object in JavaScript typically does not define a length property. When passed to _.forEach:

  1. value.length evaluates to undefined.
  2. isLength(undefined) returns false.
  3. isArrayLike(instance) resolves to false.

Because the class instance fails the array-like check, Lodash treats it as a standard key-value dictionary. It routes the instance to baseForOwn, which retrieves all own enumerable string and symbol keys via Object.keys (or Lodash’s internal keys utility) and invokes the iteratee for each property.

Prototype and Function Guards

Lodash includes explicit guards to prevent false positives: