How Lodash _.result Resolves Values and Functions
The Lodash _.result method provides a flexible way to
retrieve values from deeply nested JavaScript objects by seamlessly
handling both static properties and executable functions. This article
explores how _.result navigates nested object paths,
automatically executes functions with the correct contextual
this binding, handles missing keys through fallback values,
and compares with standard property access methods like
_.get.
Syntax and Core Mechanics
The syntax for _.result is defined as follows:
_.result(object, path, [defaultValue])object: The source object to query.path: The path of the property to resolve, defined as a string (e.g.,'a.b.c'or'users[0].name') or an array of keys (e.g.,['a', 'b', 'c']).defaultValue: An optional fallback value returned if the resolved value isundefined.
Like _.get, the method safely traverses intermediate
objects without throwing errors if a reference in the chain is
null or undefined.
Dynamic Invocation of Functions
The primary characteristic that distinguishes _.result
from _.get is how it handles functions. When resolving a
path, _.result checks the type of the resolved target:
- Static Values: If the target at the resolved path is a primitive (number, string, boolean) or a plain data structure (object, array), it is returned directly.
- Callable Functions: If the target is a function,
_.resultinvokes it immediately and returns its output.
When calling a resolved function, _.result binds the
this context to the parent object that contains the
function. This ensures methods reliant on instance state or surrounding
sibling properties execute with the expected scope.
const user = {
firstName: 'Jane',
lastName: 'Doe',
getFullName: function() {
return `${this.firstName} ${this.lastName}`;
},
role: 'Administrator'
};
// Resolving a function executes it with `this` bound to `user`
_.result(user, 'getFullName');
// => "Jane Doe"
// Resolving a standard property returns the raw value
_.result(user, 'role');
// => "Administrator"Deep Nested Traversal
When navigating deep paths, _.result resolves
intermediate keys as standard properties until it reaches the final
segment in the path. If an intermediate segment is a function, it is not
executed; only the leaf node of the designated path is evaluated for
execution.
const company = {
departments: {
engineering: {
getHeadcount: function() {
return 42;
}
}
}
};
_.result(company, 'departments.engineering.getHeadcount');
// => 42In this case, the this context inside
getHeadcount is explicitly bound to
engineering.
Handling Default Values
If the path does not exist, or if the resolved target evaluates to
undefined, _.result falls back to
defaultValue.
The defaultValue parameter also supports dynamic
resolution. If defaultValue is a function,
_.result invokes it and returns its return value:
const settings = {};
// Fallback to static value
_.result(settings, 'theme', 'dark');
// => "dark"
// Fallback to a function result
_.result(settings, 'timestamp', () => Date.now());
// => current timestamp integerIf the property exists on the object but evaluates explicitly to
null, false, or NaN,
_.result considers the property defined and will return
that value rather than evaluating the default.
_.result vs.
_.get
While _.get retrieves properties verbatim,
_.result is designed for polymorphic interfaces where an
object property might either be a static value or a getter function
depending on the application state or model architecture (such as in
Backbone.js models).
By abstracting away the check for
typeof target === 'function', _.result reduces
boilerplate code and prevents runtime errors associated with manually
checking and invoking properties across deep nested paths.