Lodash _.create Property Descriptors Explained

This article examines how the Lodash _.create method handles property descriptors when instantiating new objects from a specified prototype. While JavaScript's native Object.create accepts explicit property descriptor maps, Lodash's utility processes properties differently, resulting in standard data property attributes rather than customized descriptor configurations.

Native Object.create vs. Lodash _.create

To understand how descriptors are applied in _.create, it is essential to contrast it with native JavaScript:

Descriptors Applied by _.create

Lodash's internal implementation uses prototype inheritance (typically falling back on native Object.create(prototype)) and then copies own enumerable string-keyed properties using standard assignment semantics (baseAssign).

Because properties are assigned directly via property assignment rather than through Object.defineProperty, JavaScript attaches the default data descriptor configuration for standard assignments:

Lodash does not attach or enforce any explicit, restricted property descriptors (such as read-only or non-enumerable flags) on the newly created object.

Passing Descriptor Objects to _.create

If you pass a descriptor definition object to _.create as you would with native Object.create, Lodash treats the entire descriptor map as a literal value:

const proto = { greet() { return 'hello'; } };

// Incorrect expectation based on native Object.create:
const obj = _.create(proto, {
  name: {
    value: 'Alice',
    writable: false,
    enumerable: false
  }
});

// Resulting descriptor for 'name':
// Object.getOwnPropertyDescriptor(obj, 'name')
// returns:
// {
//   value: { value: 'Alice', writable: false, enumerable: false },
//   writable: true,
//   enumerable: true,
//   configurable: true
// }

In this scenario, obj.name evaluates to the descriptor object itself rather than the string 'Alice', and the outer property name remains fully writable, enumerable, and configurable.

Summary

When _.create builds an object from a specified prototype:

  1. It attaches no explicit, customized property descriptors.
  2. It populates properties via standard assignment, applying default descriptor states (writable: true, enumerable: true, configurable: true).
  3. To define custom flags or accessors (get/set), developers must use Object.defineProperty or native Object.create instead of _.create.