Lodash _.isPlainObject with Object.create(null)

This article examines how the Lodash JavaScript library’s _.isPlainObject function evaluates objects instantiated with Object.create(null). It covers the exact boolean result returned by the utility, the internal implementation logic that determines this outcome, and why this design choice matters when handling prototype-less dictionary objects in modern JavaScript.

The Short Answer

In modern versions of Lodash (v4.0.0 and later), calling _.isPlainObject(Object.create(null)) returns true.

Lodash treats an object with a null prototype as a plain object, alongside standard object literals ({}) and objects created directly via new Object().

const lodash = require('lodash');

const nullProtoObj = Object.create(null);
console.log(lodash.isPlainObject(nullProtoObj)); // true

const literalObj = {};
console.log(lodash.isPlainObject(literalObj)); // true

How Lodash Evaluates Object.create(null)

To understand why Object.create(null) evaluates to true, consider Lodash's definition and implementation of _.isPlainObject. Lodash defines a plain object as:

  1. An object created by the Object constructor.
  2. An object with a [[Prototype]] of null.

Internally, the _.isPlainObject algorithm follows these steps:

  1. Type and Tag Check: It verifies whether the input is "object-like" (non-null and typeof value === 'object') and that its internal [[Class]] tag matches [object Object].
  2. Null Prototype Short-Circuit: It retrieves the prototype using Object.getPrototypeOf(value). If the prototype is explicitly null, the function immediately returns true.
  3. Prototype Chain Resolution: For objects with prototypes, it traverses up the prototype chain until it reaches the top-level prototype (Object.prototype) and ensures the object's direct prototype matches this terminal prototype.

Because Object.create(null) sets the internal [[Prototype]] directly to null, it fulfills the check in step two without needing to traverse the prototype chain.

Why This Behavior Matters

In JavaScript, Object.create(null) is commonly used to create clean map or dictionary objects. Because these objects do not inherit from Object.prototype, they are free from built-in properties like toString, valueOf, or hasOwnProperty. This prevents prototype pollution and key collision vulnerabilities.

Earlier versions of utility libraries often relied strictly on checking constructor properties:

// Native naive check
function isPlain(obj) {
  return obj != null && obj.constructor === Object;
}

isPlain(Object.create(null)); // false, because obj.constructor is undefined

Because Object.create(null) lacks a constructor property, naive checks incorrectly identify it as not being a plain object. Lodash avoids this pitfall by checking prototypes directly, ensuring that clean, prototype-free key-value maps are correctly classified as plain objects.