How Lodash isPlainObject Validates Null Prototypes
Lodash’s _.isPlainObject method determines whether a
given value is a plain object—specifically, an object created by the
Object constructor or one with a [[Prototype]]
of null. This article breaks down the internal mechanics of
how Lodash checks and validates objects explicitly created with
Object.create(null), detailing the tag verification,
prototype extraction, and early return logic that permits null
prototypes while rejecting other complex object types.
The Definition of a Plain Object in Lodash
In JavaScript, a plain object is generally considered to be an object
created by literal syntax ({}) or via
new Object(). However, developers frequently use
Object.create(null) to produce clean dictionary structures
that do not inherit built-in properties from
Object.prototype, such as toString,
valueOf, or hasOwnProperty.
Lodash treats both categories as plain objects. To accommodate null prototype objects without erroneously accepting class instances, DOM nodes, or built-in objects, Lodash applies a sequence of specific internal validations.
Step 1: Base Type and Tag Verification
Before inspecting prototype chains, _.isPlainObject
ensures the input value is fundamentally shaped like an object.
isObjectLikeCheck: Lodash verifies that the value is non-null and thattypeof value === 'object'. BecauseObject.create(null)produces a non-null type of'object', it passes this gate.- Internal Tag Check: Lodash resolves the internal
[[Class]]tag of the value using an internalgetTagutility (or a fallback toObject.prototype.toString.call). For an object created withObject.create(null), the tag resolves to[object Object].
If either condition fails, the function immediately returns
false.
Step 2: Prototype Extraction
Once the object passes the preliminary type tests, Lodash retrieves its direct prototype:
const proto = Object.getPrototypeOf(value);For standard object literals ({}), proto
resolves to Object.prototype. For objects instantiated with
Object.create(null),
Object.getPrototypeOf(value) returns null.
Step 3: The Explicit Null Prototype Check
Lodash includes an explicit guard statement specifically designed for null prototypes:
if (proto === null) {
return true;
}Because proto is strictly equal to null,
this condition evaluates to true instantly. Lodash
terminates execution here and returns true, skipping all
subsequent constructor-matching logic.
Why the Short-Circuit Is Necessary
Standard plain objects undergo further verification to verify their constructor:
const Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor;
return typeof Ctor == 'function' && Ctor instanceof Ctor &&
funcToString.call(Ctor) == objectCtorString;If Lodash did not explicitly handle the proto === null
case early, attempting to access properties or call
hasOwnProperty on a null prototype would cause a
TypeError (since proto would be
null). By placing
if (proto === null) return true; before checking
proto.constructor, Lodash both avoids runtime errors and
formally accepts bare dictionary objects as valid plain objects.