How Lodash _.pull Mutates Arrays in Place

This article examines how the _.pull method in the Lodash JavaScript library operates directly on an array to remove specified elements. It explains the mechanics of in-place mutation, contrasts the method with non-destructive alternatives, outlines the internal algorithm used to alter the array reference, and highlights the performance and architectural implications of mutating data directly in JavaScript applications.

What Does In-Place Mutation Mean?

In JavaScript, mutating an array "in place" means modifying the existing array stored in memory rather than allocating and returning a new array instance. When a method mutates an array in place, any variable holding a reference to that array will immediately reflect the changes.

The _.pull method follows this pattern. Its signature is:

_.pull(array, [values])

It takes the target array as its first argument, followed by the values to remove. Instead of producing a filtered shallow copy, _.pull directly modifies the passed-in array and returns a reference to that exact same array.

const original = ['a', 'b', 'c', 'a', 'b', 'c'];
const result = _.pull(original, 'a', 'c');

console.log(original); // ['b', 'b']
console.log(result);   // ['b', 'b']
console.log(original === result); // true

How _.pull Works Under the Hood

To achieve in-place removal, Lodash iterates through the target array and checks each element against the provided set of values using the SameValueZero equality algorithm (similar to ===, but treats NaN as equal to NaN).

The internal process works as follows:

  1. Argument Extraction: Lodash gathers all arguments passed after the target array into an internal collection of values to be removed.
  2. Index Traversal: The algorithm scans the array. When an element matches one of the target values, its index is recorded.
  3. Element Shifting (Splicing): The matching element is removed by shifting subsequent elements to the left to fill the gap, directly decremented against the array's length property (similar to native Array.prototype.splice).
  4. Index Adjustment: Because elements shift left when an item is removed, the traversal index is adjusted to prevent skipping adjacent duplicates.
  5. Return Value: Lodash returns the original array reference, which now has a reduced length and contains only the un-pulled values.

Contrast With _.without

Lodash provides a non-mutating alternative called _.without. Understanding the difference highlights why _.pull is distinct:

const numbers = [1, 2, 3];

// Non-mutating
const filtered = _.without(numbers, 2);
console.log(numbers);  // [1, 2, 3]
console.log(filtered); // [1, 3]

// Mutating
_.pull(numbers, 2);
console.log(numbers);  // [1, 3]

Considerations When Using _.pull

Using _.pull can be beneficial for memory management in performance-critical scenarios involving large arrays because it avoids the overhead of allocating new array objects and triggering garbage collection.

However, in-place mutation introduces side effects. In environments that rely on immutability—such as React state management, Redux, or functional programming paradigms—mutating an array in place will bypass shallow reference equality checks, potentially preventing UI re-renders or causing unpredictable bugs. In such contexts, _.without or native .filter() should be used instead.