Array.forEach vs Lodash forEach on Sparse Arrays

This article examines the core iteration differences between native JavaScript Array.prototype.forEach and Lodash's _.forEach when handling sparse arrays. While both methods serve to iterate over collections, they handle missing elements ("holes") fundamentally differently, resulting in divergent callback execution counts, handling of undefined values, and loop termination capabilities.

Understanding Sparse Arrays

A sparse array in JavaScript is an array where certain indices have not been assigned a value, leaving "holes" rather than initialized values. These are distinct from indices explicitly set to undefined.

const sparseArray = [1, , 3]; // Index 1 is a hole, not defined

1. Handling of Missing Elements (Holes)

The primary difference between native Array.prototype.forEach and _.forEach lies in how each engine detects and treats unassigned indices.

Code Demonstration

const sparseArray = [1, , 3];

// Native Array.prototype.forEach
sparseArray.forEach((value, index) => {
  console.log(`Native: index ${index}, value ${value}`);
});
// Output:
// Native: index 0, value 1
// Native: index 2, value 3

// Lodash _.forEach
_.forEach(sparseArray, (value, index) => {
  console.log(`Lodash: index ${index}, value ${value}`);
});
// Output:
// Lodash: index 0, value 1
// Lodash: index 1, value undefined
// Lodash: index 2, value 3

2. Callback Invocation Count

Because of how holes are evaluated:

3. Early Exit Support

While not strictly limited to sparse arrays, another distinct mechanical difference during iteration is loop control:

Summary

When processing sparse arrays, native Array.prototype.forEach respects sparse definitions and skips unallocated slots, ensuring callbacks only fire for allocated indices. Conversely, Lodash's _.forEach treats sparse arrays as dense sequences of indices, iterating through every position up to length and supplying undefined for missing indices.