Prototype Keys Preserved by Lodash toPlainObject

This article examines how the Lodash utility function _.toPlainObject handles inherited properties across an object's prototype chain. It clarifies the specific criteria inherited keys must meet to be preserved during conversion, which properties are deliberately discarded, and how this affects object flattening in JavaScript applications.

The Criteria for Preserved Inherited Keys

When converting a custom class instance or an object with a prototype chain into a plain object using _.toPlainObject, Lodash does not retain the original prototype linkage. Instead, it flattens the hierarchy by copying inherited properties directly onto the new object as own properties.

To be successfully preserved and copied into the target plain object, an inherited property must meet two specific conditions:

  1. It must be enumerable: The property descriptor must have enumerable: true.
  2. It must be string-keyed: The key must be a string or a primitive that coerces into a string.

Lodash achieves this internally by resolving keys via its keysIn mechanism, which acts essentially like a for...in loop. Any property defined up the prototype chain that satisfies both conditions is extracted and assigned as an own, enumerable property on the resulting plain object.

Inherited Keys That Are Excluded

Understanding what _.toPlainObject omits is equally critical for predicting the shape of the output:

Practical Example

Consider an object created through constructor functions where prototypes are configured with different visibility:

function Parent() {}
Parent.prototype.inheritedStringKey = 'preserved'; // Enumerable: true
Object.defineProperty(Parent.prototype, 'inheritedNonEnumerable', {
  value: 'dropped',
  enumerable: false
});
Parent.prototype[Symbol('inheritedSymbol')] = 'dropped';

function Child() {
  this.ownKey = 'preserved';
}
Child.prototype = Object.create(Parent.prototype);

const instance = new Child();
const result = _.toPlainObject(instance);

In this scenario:

In summary, _.toPlainObject exclusively preserves inherited keys that are enumerable string properties, converting them from inherited prototype references into direct, own properties on a clean object instance.