Lodash _.hasIn() method
What you’ll learn
- How
_.hasIn(object, path)checks for own and inherited properties at a nested path. - Why this lets it see class methods and other prototype-side properties that
_.has()hides. - How to pick between
_.hasIn,_.has,_.get, and theinoperator. - The prototype-pollution caveat when paths come from user input.
Prerequisites
Comfortable with prototype-based inheritance in JavaScript. You should know what "own" vs "inherited" properties mean.
- Includes inherited: properties from the prototype chain count, unlike with
_.has. - Existence, not value: a present property with a falsey value still returns
true. - Prototype pollution risk: never pass unvalidated user paths—they can match
__proto__chain entries.
Overview
_.hasIn walks the path segment by segment using normal property access. Each segment is resolved through the prototype chain, so methods on a class’s prototype or properties on a mixin all count. Use it for “does this work if I read it?” checks. Use _.has when you specifically need an own-property answer.
Walks the prototype chain
Inherited methods and properties return true, just like the in operator would.
Crash-safe traversal
If an intermediate segment is null or undefined, it returns false without throwing.
Existence, not truthiness
A path containing null, 0, or "" still returns true.
Syntax
_.hasIn(object, path) - object: the object to inspect.
nullorundefinedreturnsfalse. - path: a string path (
"a.b[0]") or array path (["a", "b", 0]). - Returns:
trueif the path resolves through own or inherited properties; otherwisefalse.
Check a nested path
For plain objects with no special prototype, _.hasIn and _.has behave identically. The win shows up the moment inheritance enters the picture.
import hasIn from "lodash/hasIn";
const sample = {
user: {
details: { name: "John Doe", age: 30 },
role: "admin"
},
status: "active"
};
hasIn(sample, "user.details.age"); // -> true
hasIn(sample, "user.details.email"); // -> false
hasIn(sample, "status"); // -> true
hasIn(sample, "user.role"); // -> true Inherited properties & class methods
This is the actual difference between _.hasIn and _.has. Methods on a class’s prototype live one level up the chain—_.hasIn sees them, _.has doesn’t.
import has from "lodash/has";
import hasIn from "lodash/hasIn";
class User {
constructor(name) { this.name = name; }
greet() { return "Hi " + this.name; }
}
const u = new User("Ada");
has(u, "name"); // -> true (own)
hasIn(u, "name"); // -> true (own)
has(u, "greet"); // -> false (lives on User.prototype)
hasIn(u, "greet"); // -> true (chain includes prototype)
has(u, "toString"); // -> false (Object.prototype)
hasIn(u, "toString"); // -> true Falsey values & array paths
Existence is independent of value. Array paths are necessary when a key literally contains a dot or bracket.
import hasIn from "lodash/hasIn";
const config = {
retries: 0,
enabled: false,
notes: "",
items: [{ id: 1 }],
"x.y": { z: 42 }
};
hasIn(config, "retries"); // -> true (0 is still present)
hasIn(config, "enabled"); // -> true (false is still present)
hasIn(config, "notes"); // -> true ("" is still present)
hasIn(config, "items[0].id"); // -> true
hasIn(config, ["x.y", "z"]); // -> true (literal dotted key)
hasIn(config, "x.y.z"); // -> false (splits into x.y.z)
hasIn(config, "missing"); // -> false 📋 _.hasIn vs related checks
| Topic | _.hasIn | _.has | in operator | Object.hasOwn() |
|---|---|---|---|---|
| Nested paths | Yes | Yes | No | No |
| Own properties | Yes | Yes | Yes | Yes |
| Inherited properties | Yes | No | Yes | No |
| Returns value | No, boolean | No, boolean | No, boolean | No, boolean |
| Falsey values | Still true if present | Still true if present | Still true if present | Still true if present |
Reach for _.hasIn when inherited surface is part of the API. Use _.has when the answer should ignore the prototype chain. Use the native in operator or Object.hasOwn() for single-level checks where no path resolution is needed.
Pitfalls to avoid
Inherited matches can be surprising
hasIn({}, "toString") is true because toString lives on Object.prototype. If that surprises you, use _.has.
Risk with user-supplied paths
Because _.hasIn walks the prototype chain, a polluted Object.prototype can produce false positives. Validate paths against an allow-list.
Existence is not truthiness
A property whose value is false or 0 still satisfies _.hasIn. Don’t use it where you mean “is this enabled?”.
Dotted keys need array paths
"x.y.z" means three segments. Use ["x.y", "z"] if "x.y" is one literal key.
❓ FAQ
Summary
- Purpose: check whether a path exists, including inherited properties.
- Remember: the difference from
_.hasis the prototype chain—not nesting. Both accept nested paths. - Next: Lodash _.invert(), _.has(), or the official Lodash docs for _.hasIn.
_.hasIn walks the prototype chain just like a normal property lookup. That means inherited properties—including ones added to Object.prototype—will return true. Stick with _.has when only own properties should count.
5 people found this page helpful
