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)object: The target object to modify.path: The path of the property to update. This can be expressed as a dot-notated string (e.g.,'a.b.c'), an array notation string (e.g.,'a[0].b'), or an array of property names/indices (e.g.,['a', 0, 'b']).updater: The function invoked to produce the updated value. It receives the existing value at the path as its single argument:(currentValue) => newValue.
How _.update
Operates Under the Hood
When _.update is invoked, it follows a specific sequence
of operations:
- Path Resolution: Lodash parses the provided path into segments. It navigates down the object structure step-by-step.
- 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 undefinedexceptions. - 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. - Executing the Updater: The updater function is executed with the retrieved value passed in as the first argument.
- 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: 6Handling 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.