How Lodash _.update Modifies Values by Path

The _.update method in the Lodash JavaScript library provides a clean, functional approach to updating deeply nested properties within an object. Instead of manually traversing nested keys and assigning a new static value, _.update takes an object, a path, and an updater function. It retrieves the current value located at the specified path, passes that value into the updater function, and writes the returned result directly back to that path, mutating the source object.

Syntax and Core Arguments

The syntax for _.update is:

_.update(object, path, updater)

How _.update Operates Under the Hood

When _.update is invoked, it follows a specific sequence of operations:

  1. Path Resolution: Lodash parses the provided path into segments. It navigates down the object structure step-by-step.
  2. Path Creation (if missing): If any intermediate segment in the path does not exist, Lodash automatically creates an empty object (or an array, if a segment is numeric) to prevent TypeError: Cannot read properties of undefined exceptions.
  3. Retrieving Current Value: Lodash extracts the current value located at the final destination key. If the key does not exist, the resolved value is undefined.
  4. Executing the Updater: The updater function is executed with the retrieved value passed in as the first argument.
  5. Assignment and Return: The return value of the updater function is assigned to the target property. The original object is mutated and returned.

Code Example: Modifying Existing Values

In standard JavaScript, mutating a nested value requires defensive checks to avoid runtime errors. _.update handles this traversal cleanly:

const _ = require('lodash');

const state = {
  user: {
    profile: {
      loginCount: 5
    }
  }
};

// Increment the login count
_.update(state, 'user.profile.loginCount', count => count + 1);

console.log(state.user.profile.loginCount);
// Output: 6

Handling Missing Paths and Arrays

If the path does not exist, _.update supplies undefined to the updater function and builds the necessary object structure automatically:

const data = {};

// Updating a non-existent path
_.update(data, 'inventory.items[0].quantity', (quantity = 0) => quantity + 10);

console.log(data);
// Output: { inventory: { items: [ { quantity: 10 } ] } }

In this example, default parameter values (quantity = 0) can be used inside the updater function to handle the initial undefined state safely.

_.update vs _.set

While _.set also writes values to deep paths, it requires the caller to supply the final static value upfront. _.update is designed specifically for scenarios where the new value depends on the previous state (such as incrementing counters, toggling booleans, or appending elements to an array), eliminating the need for an intermediate _.get call.