JavaScript Interview Prep
Prototypes & Inheritance

Object.create()

Direct Control Over the Prototype

LinkedIn Hook

new is not the only way to build an object.

Object.create(proto) lets you hand-pick which object sits in the prototype chain — no constructor function required, no side effects, no arguments to worry about. It's the cleanest inheritance primitive JavaScript has.

And then there's Object.create(null) — a superpower most devs never use. It creates an object with ZERO prototype chain. No toString, no hasOwnProperty, no constructor, nothing. A perfectly safe dictionary, immune to prototype pollution.

Interviewers love Object.create because writing its polyfill forces you to understand what new really does: make a blank object, link its __proto__, and run a constructor.

In this lesson you'll learn the three most common Object.create patterns (basic, null, and with property descriptors), how to build your own polyfill, and why seasoned JS devs often reach for Object.create over new.

Read the full lesson -> [link]

#JavaScript #InterviewPrep #ObjectCreate #Prototypes #Frontend #CodingInterview #WebDevelopment


Object.create() thumbnail


What You'll Learn

  • How Object.create(proto) builds an object whose __proto__ is exactly the prototype you pass
  • Why Object.create(null) gives you a truly empty object with no prototype chain
  • How to write a polyfill for Object.create and what it teaches you about new

Object.create — The Cleanest Way to Set a Prototype

Object.create() is the cleanest way to create objects with a specific prototype. It takes a prototype object as its first argument and returns a brand new object whose __proto__ points to that prototype.

Basic Usage

const animal = {
  alive: true,
  eat() {
    return this.name + " is eating";
  }
};

const dog = Object.create(animal);
dog.name = "Rex";

console.log(dog.eat());   // "Rex is eating" (inherited from animal)
console.log(dog.alive);   // true (inherited)
console.log(dog.name);    // "Rex" (own property)

// The chain:
console.log(dog.__proto__ === animal); // true
console.log(animal.__proto__ === Object.prototype); // true

Object.create(null) — Truly Empty Objects

This is a powerful pattern for creating objects with absolutely NO prototype chain. No toString, no hasOwnProperty, no constructor — nothing.

const dict = Object.create(null);

dict.hello = "world";

console.log(dict.hello); // "world"
console.log(dict.toString); // undefined (no prototype!)
console.log(dict.hasOwnProperty); // undefined
console.log(dict.__proto__); // undefined

// Useful for:
// 1. Safe dictionaries (no prototype pollution)
// 2. Map-like objects where you don't want inherited properties
// 3. JSON-like data stores

// Compare with regular object:
const regular = {};
console.log(regular.toString); // [Function: toString] (inherited)
console.log("toString" in regular); // true (inherited from Object.prototype)

const clean = Object.create(null);
console.log("toString" in clean); // false (truly empty)

Object.create with Property Descriptors

const person = {
  greet() {
    return "Hi, I'm " + this.name;
  }
};

const rakibul = Object.create(person, {
  name: {
    value: "Rakibul",
    writable: true,
    enumerable: true,
    configurable: true
  },
  age: {
    value: 25,
    writable: false, // read-only
    enumerable: true,
    configurable: false
  }
});

console.log(rakibul.greet()); // "Hi, I'm Rakibul"
console.log(rakibul.age);     // 25

rakibul.age = 30; // Fails silently (strict mode would throw)
console.log(rakibul.age); // 25 (unchanged)

Practical Pattern — Prototype-Based Inheritance with Object.create

// Base object (acts like an "abstract class")
const Shape = {
  init(type) {
    this.type = type;
    return this; // for chaining
  },
  describe() {
    return "I am a " + this.type;
  }
};

// "Subclass" via Object.create
const Circle = Object.create(Shape);
Circle.init = function (radius) {
  Shape.init.call(this, "circle"); // delegate to parent
  this.radius = radius;
  return this;
};
Circle.area = function () {
  return Math.PI * this.radius * this.radius;
};

// Create instances by cloning Circle
const c1 = Object.create(Circle).init(5);
const c2 = Object.create(Circle).init(10);

console.log(c1.describe()); // "I am a circle" (from Shape)
console.log(c1.area());     // 78.539...
console.log(c2.area());     // 314.159...

// Chain: c1 -> Circle -> Shape -> Object.prototype -> null

Polyfill for Object.create

This is a classic interview question:

if (!Object.create) {
  Object.create = function (proto, propertiesObject) {
    if (typeof proto !== "object" && typeof proto !== "function") {
      throw new TypeError("Object prototype may only be an Object or null");
    }

    // Create a temporary constructor
    function F() {}
    F.prototype = proto;

    // Create new instance (its __proto__ will be proto)
    const obj = new F();

    // Handle null prototype
    if (proto === null) {
      obj.__proto__ = null;
    }

    // Add properties if provided
    if (propertiesObject !== undefined) {
      Object.defineProperties(obj, propertiesObject);
    }

    return obj;
  };
}

Object.create() visual 1


Common Mistakes

  • Assuming Object.create(proto) runs any kind of constructor — it does not. It only links the prototype. If you need initialization, call an init method manually or use new.
  • Using a regular {} as a dictionary, then being surprised when toString, constructor, or __proto__ show up as "keys" — use Object.create(null) for true maps.
  • Forgetting that property descriptors in the second argument default to writable: false, enumerable: false, configurable: false — omitting those flags creates read-only, non-enumerable properties.

Interview Questions

Q: What does Object.create(null) do and why is it useful?

It creates an object with absolutely no prototype — not even Object.prototype. This means no inherited properties like toString or hasOwnProperty. It's useful for creating safe dictionaries/maps where you don't want prototype pollution or accidental collisions with inherited properties.

Q: Write a polyfill for Object.create.

Create a temporary constructor function, set its .prototype to the given prototype object, then return new F(). This creates a new object whose __proto__ is the provided prototype. Handle the null case by explicitly setting __proto__ = null, and apply Object.defineProperties if the second argument is provided.

Q: What is the difference between Object.create(proto) and new Constructor()?

Object.create(proto) creates an empty object with proto as its __proto__. It doesn't call any constructor function. new Constructor() creates a new object, sets its __proto__ to Constructor.prototype, AND runs the constructor function (initializing properties).


Quick Reference — Cheat Sheet

OBJECT.CREATE — QUICK MAP

Object.create(proto)
  -> new empty object, __proto__ = proto
  -> no constructor runs

Object.create(null)
  -> truly empty (no prototype chain)
  -> ideal for dictionaries / maps
  -> no toString, no hasOwnProperty, nothing inherited

Object.create(proto, descriptors)
  -> also defines properties via Object.defineProperties
  -> defaults: writable=false, enumerable=false, configurable=false

Polyfill (sketch):
  function F() {}
  F.prototype = proto;
  return new F();   // __proto__ === proto

vs new Constructor():
  new   -> allocate + link __proto__ + run constructor
  Object.create -> allocate + link __proto__ only

Previous: Prototypal Inheritance Next: ES6 Classes (Syntactic Sugar)


This is Lesson 5.3 of the JavaScript Interview Prep Course — 14 chapters, 87 lessons.

On this page