How Lodash _.set Parses Bracket Notation Paths

Lodash’s _.set method allows developers to modify or create deeply nested object properties using string paths that support both dot notation and bracket notation. Under the hood, Lodash transforms these string paths into structured arrays of property keys using an internal parser known as stringToPath. This article breaks down the internal regular expressions, string tokenization, escaping rules, and memoization techniques Lodash uses to parse bracket notation into property accessors.

The Path Normalization Pipeline

When you call _.set(object, path, value), Lodash does not directly manipulate the string while traversing the object. Instead, it normalizes the path into an array of keys using an internal helper function named castPath.

If path is already an array (such as ['a', '0', 'b']), Lodash uses it directly. If the path is a string (such as a[0].b or a['complex.key'][1]), Lodash delegates the string parsing to the internal stringToPath function.

The Regular Expression Engine

At the core of stringToPath is a complex regular expression designed to match property identifiers, bracketed indices, and quoted bracketed strings while handling edge cases like escaped characters. In Lodash v4, this expression is defined as rePropName:

const rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g;

This regular expression matches three primary token patterns sequentially across the string:

  1. Standard Unbracketed Properties ([^.[\]]+): Matches standard property names separated by dots, stopping whenever it encounters a dot (.) or an opening/closing bracket ([ or ]).
  2. Bracketed Values (\[...\]):
    • Numeric Indices (-?\d+(?:\.\d+)?): Matches unquoted integers or floats placed inside brackets, such as [0] or [-1].
    • Quoted Property Names ((["'])((?:(?!\2)[^\\]|\\.)*?)\2): Matches single- or double-quoted strings inside brackets, such as ['foo'] or ["bar"]. It captures the quote type in a backreference and matches any character until the matching closing quote, respecting backslash escapes (e.g., ['escaped\'quote']).
  3. Empty Brackets or Empty Segments ((?=(?:\.|\[\])(?:\.|\[\]|$))): A lookahead group that captures empty segments like [], which are normalized to empty string keys.

Token Processing and Unescaping

As stringToPath executes RegExp.prototype.replace or match iterations using rePropName, it processes each matched segment into a sanitized string key:

For example, the path string:

"users[0]['first.name']"

is parsed into three discrete array elements:

["users", "0", "first.name"]

Because first.name was wrapped in quotes inside brackets, the parser treats the dot as a literal character rather than a path delimiter.

Memoization for Performance

Parsing strings with complex regular expressions can introduce performance bottlenecks if executed repeatedly. To avoid this overhead, Lodash wraps stringToPath in a memoization function (memoizeCachable).

Parsed paths are stored in an internal MapCache (capped at 500 entries). When _.set is called multiple times with the exact same path string, the regular expression engine is bypassed entirely after the first invocation, returning the cached array of segment keys instantly.

Path Application in _.set

Once the path string is fully decomposed into an array of string keys, _.set traverses the target object step-by-step. If an intermediate property does not exist, Lodash checks the upcoming key: if the next key parses as an integer index, Lodash initializes that property as an empty array ([]); otherwise, it initializes it as a plain object ({}). This ensures that paths like items[0] correctly build array structures, while items['0'] and items[0] are evaluated symmetrically.