How Lodash _.range Generates Sequential Arrays
The Lodash _.range method is a utility function designed
to dynamically produce arrays of numbers progressing from a defined
start point up to, but not including, an end point by a specified step
increment. It provides a clean, declarative alternative to manual
for loops for generating sequences, handling arithmetic
progression, edge cases, and memory pre-allocation under the hood. This
article explains the syntax, algorithmic mechanics, and internal
behaviors that allow _.range to generate sequential arrays
efficiently.
Method Signature and Parameters
The _.range method accepts up to three numeric
arguments:
_.range([start=0], end, [step=1])start(number, optional): The beginning of the sequence. Defaults to0if omitted.end(number): The ceiling of the sequence. The returned array will include values strictly less than this boundary (or strictly greater than this boundary if the step is negative).step(number, optional): The increment or decrement value between elements. Defaults to1(or-1ifendis less thanstart).
How Argument Normalization Works
To allow flexibility, Lodash normalizes its arguments dynamically before producing the array:
Single Argument Call: If only one argument is provided, Lodash interprets it as the
endvalue, settingstartto0andstepto1(or-1if the single argument is negative)._.range(4)evaluates to[0, 1, 2, 3]._.range(-4)evaluates to[0, -1, -2, -3].
Two Argument Call: Providing two arguments designates them as
startandend. Thestepautomatically becomes1ifstart < end, or-1ifstart > end._.range(1, 5)evaluates to[1, 2, 3, 4].
Three Argument Call: Specifying all three parameters explicitly defines the progression.
_.range(0, 20, 5)evaluates to[0, 5, 10, 15]._.range(0, -4, -1)evaluates to[0, -1, -2, -3].
Internal Mechanics and Array Construction
Under the hood, _.range constructs the array via a
deterministic sequence of steps:
1. Length Calculation
Before creating the array, the function calculates the required
length using the difference between end and
start divided by the step:
\[\text{length} = \max\left(\left\lceil \frac{\text{end} - \text{start}}{\text{step}} \right\rceil, 0\right)\]
If step is 0, Lodash avoids infinite loops
by using the calculated span to create an array filled repeatedly with
the start value up to the designated length.
2. Fixed-Length Memory Allocation
Instead of pushing values onto a dynamically expanding array—which requires frequent memory reallocations by the JavaScript engine—Lodash initializes an array with the exact pre-calculated length:
const result = new Array(length);3. Linear Population
A standard while loop then iterates through the indices from
0 to length - 1. During each iteration, the
value at result[index] is set to:
\[\text{value} = \text{start} + (\text{index} \times \text{step})\]
This arithmetic calculation prevents accumulated floating-point
inaccuracies that often occur when using repeated addition
(current += step).
Handling Edge Cases
- Empty Ranges: If
startequalsend, or if the direction ofstepcontradicts the progression (e.g.,_.range(1, 4, -1)), the calculated length evaluates to0or less, immediately returning an empty array[]. - Zero Step: When a step of
0is explicitly passed (e.g.,_.range(1, 4, 0)), Lodash treats the step as zero without error, returning[1, 1, 1]based on the iteration count. - Non-Integer Values: The method natively supports
floating-point increments:
_.range(0, 1, 0.2)generates[0, 0.2, 0.4, 0.6, 0.8].