How Object.create Establishes Prototypes in JS

This article explains how JavaScript’s Object.create() method creates and manages prototype links between objects. You will learn the mechanics behind the hidden [[Prototype]] reference, how the prototype chain performs property lookups, how to define additional properties using property descriptors, and why this method provides a direct approach to object inheritance compared to standard constructor functions.


The Fundamental Mechanism

In JavaScript, objects inherit properties and methods through a mechanism called the prototype chain. Every JavaScript object has an internal hidden link, known in ECMAScript specifications as [[Prototype]] (accessible in most runtime environments via __proto__ or Object.getPrototypeOf()).

When you invoke Object.create(proto), JavaScript creates a completely new, empty object and sets its internal [[Prototype]] reference directly to the proto object passed in the first argument.

const parent = {
  greet() {
    return "Hello from parent";
  }
};

// Create a new object with 'parent' as its prototype
const child = Object.create(parent);

console.log(child.greet()); // "Hello from parent"
console.log(Object.getPrototypeOf(child) === parent); // true

Property Delegation and Lookup

Object.create() does not copy properties from the source object to the new object. Instead, it relies on delegation:

  1. When accessing a property on child (e.g., child.greet), the JavaScript engine checks if the property exists directly on child (as an “own property”).
  2. If it is not found on child, the engine traverses the internal [[Prototype]] link to parent.
  3. If found on parent, that value or method is executed.
  4. If not found, the engine continues up the chain to Object.prototype and eventually returns undefined if the root of the chain (null) is reached.

Defining Properties with Descriptors

Object.create() accepts an optional second argument that allows you to define own properties on the newly created object using property descriptors.

const personProto = {
  describe() {
    return `Name: ${this.name}`;
  }
};

const user = Object.create(personProto, {
  name: {
    value: "Alex",
    writable: true,
    enumerable: true,
    configurable: true
  }
});

console.log(user.describe()); // "Name: Alex"
console.log(user.hasOwnProperty("name")); // true

Creating Objects Without a Prototype

A distinctive capability of Object.create() is its ability to create a “pure dictionary” object with no prototype link whatsoever by passing null.

const bareObject = Object.create(null);

console.log(Object.getPrototypeOf(bareObject)); // null
console.log(bareObject.toString); // undefined (does not inherit from Object.prototype)

This prevents prototype pollution and ensures that default methods like toString or hasOwnProperty do not collide with user-defined keys.

Object.create() vs Constructor Functions

Traditional inheritance using constructor functions relies on the new operator and the constructor’s .prototype property:

function Parent() {}
Parent.prototype.greet = function() { return "Hi"; };

const child = new Parent();

Object.create() bypasses the constructor function entirely, allowing direct object-to-object linkage. It cleanly separates object creation from initialization, establishing explicit inheritance with minimal overhead.