How Lodash _.rest Handles Fewer Arguments

This article explains how the Lodash utility _.rest processes trailing arguments when a wrapped function is invoked with fewer arguments than expected. In short, when the number of supplied arguments does not reach the designated rest parameter index, Lodash calculates a non-negative length of zero, resulting in an empty array ([]) being passed as the trailing parameter rather than null or undefined.

The Mechanics of _.rest

The _.rest method wraps a function so that any arguments provided from a specified start index onward are collected into a single trailing array. By default, the start index is derived from the function's arity, specifically func.length - 1.

When the wrapped function executes, Lodash dynamically determines the size of this rest array by evaluating the total number of passed arguments against the defined start index:

var length = Math.max(args.length - start, 0);

Behavior When Arguments Fall Short

If a caller provides fewer arguments than the start position specifies, args.length - start evaluates to a negative number. Because of the Math.max(..., 0) constraint, Lodash safely clamps the length to 0.

From there, the internal logic constructs the rest array:

  1. Array Allocation: Lodash initializes a new array of size 0 (Array(length)).
  2. Element Population: Since the loop boundary is determined by length (which is 0), the loop terminates immediately without inserting elements.
  3. Invocation: The original function is invoked with the positional arguments mapped sequentially, followed by the empty array.

Any positional arguments that were defined prior to the rest parameter but were omitted by the caller simply receive undefined, consistent with standard JavaScript function call behavior.

Code Example

Consider a function expecting two regular parameters and a rest parameter:

const _ = require('lodash');

const fn = _.rest(function(a, b, restArgs) {
  return { a, b, restArgs };
});

// fn.length is 3, so start defaults to index 2 (the 3rd parameter)
console.log(fn('only-one'));
// Output: { a: 'only-one', b: undefined, restArgs: [] }

console.log(fn());
// Output: { a: undefined, b: undefined, restArgs: [] }

Regardless of whether the caller passes zero arguments or just enough to satisfy some of the positional slots, restArgs is guaranteed to be an empty array ([]). This design mirrors native ES6 rest parameters, ensuring predictable array operations like .map() or .length can be executed on the trailing parameter without throwing TypeError exceptions.