Lodash _.invoke() method
What you’ll learn
- How
_.invoke(object, path, [...args])calls a method at a nested path and returns its result. - Why
thisinside the invoked method is the method’s direct parent on the resolved path. - How
_.invokediffers from the often-confused_.invokeMap(the collection variant). - How missing paths are handled safely (no throw—just
undefined).
Prerequisites
Comfortable with _.get()-style nested paths and how this works in method calls.
- Single object, single call: not a batch operation. For batches use
_.invokeMap. - Path syntax: dotted strings, bracket strings, or array paths—same rules as
_.get. - Missing-path safe: missing method paths return
undefined. Guard paths that may resolve to non-functions.
Overview
_.invoke resolves a path on an object, finds a function at the end, and calls it. The function is invoked with this set to the path’s parent, exactly like a regular dotted call would have done—but without the TypeError when something in the path is missing.
Path-based call
String or array path resolves to the function; remaining arguments are forwarded to it.
Missing-path safe
If the method path is missing, you get undefined back instead of a missing-property crash.
Correct this
No manual binding needed—the parent of the path is automatically the receiver.
Syntax
_.invoke(object, path, [...args]) - object: the source to walk.
nullorundefinedreturnsundefined. - path: string (
"a.b[0].do") or array (["a", "b", 0, "do"]) describing where the method lives. - ...args: arguments forwarded to the method when it’s called.
- Returns: the method’s return value, or
undefinedwhen the method path is missing. If the path exists but is not callable, guard it first.
Call a method at a nested path
The canonical use case—walk a string path, call the function you find, get back the result. Note how this is automatically the path’s parent object.
import invoke from "lodash/invoke";
const data = {
a: [{
b: {
c: [1, 2, 3, 4, 5]
}
}]
};
invoke(data, "a[0].b.c.slice", 1, 3);
// -> [2, 3]
// `this` is data.a[0].b.c when slice runs.
invoke(data, ["a", 0, "b", "c", "join"], "-");
// -> "1-2-3-4-5"
invoke(data, "a[0].b.c.reverse");
// -> [5, 4, 3, 2, 1] (reverse mutates the source array) Automatic this binding
When the method reads this, it sees the path’s parent. That is what makes _.invoke different from calling the function in isolation.
import invoke from "lodash/invoke";
const user = {
name: "Ada",
profile: {
fullName: "Ada Lovelace",
toJSON() {
return { name: this.fullName };
}
}
};
invoke(user, "profile.toJSON");
// -> { name: "Ada Lovelace" }
// `this` was user.profile.
// For comparison, call the function with the wrong receiver:
const fn = user.profile.toJSON;
fn.call({});
// -> { name: undefined } (this.fullName is now undefined) Missing paths, guarded non-functions, batch operations
Three behaviours to remember: missing method paths return undefined, existing non-function values should be guarded before calling, and _.invoke is not the batch variant.
import invoke from "lodash/invoke";
import invokeMap from "lodash/invokeMap";
import get from "lodash/get";
const partial = { name: "Bob" };
invoke(partial, "greet");
// -> undefined (no method, no crash)
invoke(partial, "name.toUpperCase");
// -> "BOB" (works because strings have methods)
const maybeLength = get(partial, "name.length");
typeof maybeLength === "function" ? invoke(partial, "name.length") : undefined;
// -> undefined (guarded because length is a number, not a function)
// Need to call greet() on every user? That's _.invokeMap:
const users = [
{ greet() { return "Hi from A"; } },
{ greet() { return "Hi from B"; } }
];
invoke(users, "greet");
// -> undefined (users is an array; users.greet doesn't exist)
invokeMap(users, "greet");
// -> ["Hi from A", "Hi from B"] (this is what we wanted) 📋 _.invoke vs related helpers
| Topic | _.invoke | _.invokeMap | _.get | Direct call |
|---|---|---|---|---|
| Input | Single object | Collection (array or object) | Single object | Anything |
| What it does | Calls one method | Calls the method on each element | Reads a value | Calls one method |
| Missing-path safe | Yes | Yes | Yes | No |
Preserves this | Yes (auto) | Yes (per element) | N/A | Yes (manually) |
| Returns | Method result | Array of results | Resolved value | Whatever you wrote |
Reach for _.invoke when a single dynamic path may not exist. Reach for _.invokeMap when you have many elements that all share the same method name. Reach for _.get when you don’t need to call anything.
Pitfalls to avoid
Not a batch helper
It's tempting to pass an array as the first argument. That calls a method on the array, not on each element. Use _.invokeMap for collections.
Literal dots in keys need array paths
invoke(obj, "x.y.do") resolves three segments. Use ["x.y", "do"] if "x.y" is one literal key.
Don’t feed user-supplied paths blindly
A dynamic path can resolve to dangerous functions on the prototype chain. Validate against an allow-list before invoking.
Methods can still mutate
_.invoke doesn’t isolate the call—methods like Array.prototype.reverse still mutate the underlying array.
❓ FAQ
Summary
- Purpose: call a method at a nested path on a single object with correct
this. - Remember: for many objects, use
_.invokeMap. For just reading, use_.get. - Next: Lodash _.keys(), _.get(), or the official Lodash docs for _.invoke.
_.invoke calls one method at a path on one object. If you want to call the same method on every element of a collection, that’s a different helper—_.invokeMap.
5 people found this page helpful
