Historical Context & Motivation
Most programming languages you may have heard of — like Java or Python — use classes as blueprints to create objects. JavaScript took a different road. When Brendan Eich designed the language in 1995, he chose a prototype-based approach, meaning objects are created directly from other objects rather than from abstract templates. This design choice was inspired by a lesser-known language called Self, and it gives JavaScript a unique flexibility that can feel strange at first but is incredibly powerful once you understand it.
For years, JavaScript developers used constructor functions and the new keyword to create objects. While this worked, it often confused people because it tried to mimic classical inheritance without truly being classical. The community needed a cleaner, more explicit way to create objects that embraced JavaScript's true nature. That need led to Object.create, introduced in ECMAScript 5 (2009), which lets you create a new object and directly specify its prototype — the object it inherits from.
Object.create() becomes an official part of the language, giving developers a clean, explicit way to set up prototype chains.class keyword, but under the hood it still uses prototypes. Understanding Object.create helps you see what classes really do.So the big question this lesson answers is: How can you create a new object that automatically shares behavior from an existing object, without needing a class or constructor? That is exactly what Object.create does.
Core Principles & Definitions
Before diving into code, let's lock down a few ideas. In JavaScript, every object can have a hidden link to another object — this link is called its prototype. When you ask an object for a property it doesn't own, JavaScript follows that link and checks the prototype. If the prototype doesn't have it either, JavaScript follows the prototype's prototype, and so on. This chain of links is called the prototype chain. The method Object.create(proto) creates a brand-new, empty object whose prototype is set to proto.
Prototype
Prototype Chain
null.Object.create(proto)
proto. No constructor function is needed.Own Properties vs. Inherited
Delegation, Not Copying
Object.create does not copy properties. The child delegates to the parent at runtime, keeping a live link.Object.create works the same way: the new object doesn't copy all the properties — it just knows where to look them up when needed. If the family account adds a new show, you see it immediately because the link is live.Visual Explanation — The Prototype Chain
speak() and eat(). The dog object was created with Object.create(animal), so it has its own breed property but delegates method calls up the dashed arrow to animal.Notice that dog never received a copy of speak(). When you call dog.speak(), JavaScript first checks dog itself. Finding nothing, it follows the hidden [[Prototype]] link (the dashed arrow) up to animal, where speak() lives. This process is called delegation — the child object delegates the work to its prototype. If animal didn't have it either, JS would keep climbing until it reaches null (the end of the chain) and then return undefined.
How Object.create Works Under the Hood
The syntax for Object.create is straightforward. It takes one required argument — the object that should become the new object's prototype — and one optional argument for defining additional properties. For this introductory lesson, we'll focus on the first argument.
null). The returned child is a new, empty object whose internal [[Prototype]] points to prototypeObject.Let's trace what happens in memory when this code runs. First, JavaScript allocates a fresh, empty object — no properties of its own. Then it sets the internal [[Prototype]] slot of this new object to reference prototypeObject. That's it — no constructor function is invoked, no new keyword is needed. The result is a clean, direct prototype link.
Adding Own Properties After Creation
Because the object starts empty, you'll usually assign own properties right after creating it. These are properties that belong only to this specific object, not shared through the prototype. Here's a quick pattern:
breed and name are own properties of dog. Methods like speak() and eat() are inherited from animal.Property Shadowing
What if dog defines a property with the same name as one on animal? For example, if you write dog.type = "dog", JavaScript won't modify animal.type. Instead, it creates a new own property on dog that shadows (hides) the inherited one. This is called property shadowing and it means each object can customize behavior without affecting the prototype.
Object.create vs. Other Object Creation Methods
JavaScript gives you several ways to create objects, and it's important to understand how Object.create compares to the alternatives. The diagram below maps three common approaches side by side, showing what each produces in terms of own properties and prototype links.
Object.create stands out because you choose exactly which object becomes the prototype, giving you fine-grained control over the inheritance chain.| Feature | Object Literal | Object.create | Constructor + new |
|---|---|---|---|
| Custom prototype? | No — always Object.prototype | Yes — you choose | Yes — via .prototype property |
| Runs a function? | No | No | Yes — the constructor |
| Starts empty? | No — has defined properties | Yes — truly empty | No — constructor sets properties |
| Best for | Quick one-off objects | Setting up inheritance chains | Creating many similar objects |
Worked Example — Building a Vehicle Hierarchy
Let's walk through a complete example step by step. We'll create a vehicle prototype and then use Object.create to build a car that inherits from it.
vehicle that holds shared properties and methods. This object will act as the prototype for all vehicles.
const vehicle = { wheels: 4, start() { return "Engine started!"; }, describe() { return this.make + " " + this.model; } };vehicle has wheels, start(), and describe()Object.create(vehicle) to make a new object whose prototype is vehicle. At this point, car is an empty object.
const car = Object.create(vehicle);car → empty, prototype → vehiclecar its own unique data. These properties belong only to car and won't affect vehicle.
car.make = "Toyota"; car.model = "Camry"; car.year = 2024;car now owns make, model, yearcar.start() works even though car doesn't have its own start method. JavaScript delegates up the prototype chain to vehicle.
car.start(); // "Engine started!"vehiclecar.describe() calls vehicle.describe(), but this inside the method refers to car, not vehicle. So it reads car.make and car.model.
car.describe(); // "Toyota Camry"this binds to the calling objectdescribe() is defined on vehicle, when called as car.describe(), the this keyword refers to car. This means inherited methods can read the child's own properties — making shared methods reusable across many different objects.Strengths & Limitations of Object.create
Like any tool, Object.create has its sweet spots and its rough edges. Understanding both will help you choose the right approach when writing real code.
| Strengths ✅ | Limitations ⚠️ |
|---|---|
| Explicit and readable — you can clearly see which object is the prototype. | The created object starts empty, so you must manually add every own property. |
| No constructor function required — simpler mental model. | No built-in way to run initialization logic (like a constructor does). |
| Works with any object, including plain objects and null. | Sharing mutable data (arrays, nested objects) on the prototype can cause unexpected side effects. |
| Great for building prototype chains for delegation. | Less familiar to developers coming from class-based languages like Java or C++. |
| Helps you understand what ES6 classes do under the hood. | For large projects, ES6 class syntax is often preferred for consistency. |
Object.create like getting a blank phone case that clips onto a specific phone model. The case (new object) starts with nothing on it, but it's shaped to fit that particular phone (its prototype). You can decorate the case however you like (add own properties), and the phone's built-in features (inherited methods) are always accessible through it. The tradeoff? You have to add the decorations yourself — they don't come pre-applied.Connection to ES6 Classes and Advanced Patterns
In 2015, JavaScript introduced the class keyword with ES6. Many beginners assume that classes and Object.create are completely different systems. In reality, ES6 classes are syntactic sugar over the same prototype mechanism. When you write class Dog extends Animal, JavaScript uses Object.create behind the scenes to link Dog.prototype to Animal.prototype.
| Feature | Object.create (this lesson) | ES6 class (advanced) |
|---|---|---|
| Syntax style | Functional — just method calls | Declarative — class keyword |
| Constructor | None (add properties manually) | constructor() method runs automatically |
| Inheritance | Object.create(proto) | extends ParentClass |
| Under the hood | Direct prototype linkage | Also uses prototype linkage! |
| When to use | Learning prototypes, simple delegation | Larger apps, team projects, familiar syntax |
Understanding Object.create now gives you a huge advantage later. When you encounter ES6 classes, you'll know that extends is just calling Object.create internally. You'll also be able to debug tricky inheritance issues by inspecting the prototype chain directly. In advanced patterns like Object Linking to Other Objects (OLOO), developers use Object.create exclusively — no classes, no constructors — to build clean, composable code.
Practice Problems
Object.create(someObj), does the new object receive copies of someObj's properties? Explain what actually happens.puppy.sound return? Explain your reasoning.
const pet = { sound: "generic noise", legs: 4 };
const puppy = Object.create(pet);
puppy.sound = "woof";console.log statement below and explain why:
const shape = { sides: 0, describe() { return "I have " + this.sides + " sides."; } };
const triangle = Object.create(shape);
triangle.sides = 3;
const square = Object.create(shape);
square.sides = 4;
console.log(triangle.describe());
console.log(square.describe());
console.log(shape.describe());character prototype with properties health: 100 and a method takeDamage(amount) that subtracts amount from this.health. Then create a warrior using Object.create that has name: "Aria" and weapon: "sword". What is warrior.health after calling warrior.takeDamage(25)?Object.create is pointless now that JavaScript has ES6 classes. You should never use it." Do you agree or disagree? Write 3–4 sentences defending your position, and give at least one scenario where Object.create might be the better choice.Lesson Summary
Object.create(proto) creates a new, empty object whose internal prototype is set to proto. This establishes a prototype chain — a live link that JavaScript follows when looking up properties the object doesn't own. This process is called delegation, and it means inherited methods like speak() are shared, not copied. When a child object defines a property with the same name as one on its prototype, property shadowing ensures the child's version is used without altering the prototype.
Compared to object literals and constructor functions, Object.create gives you the most explicit control over which object becomes the prototype. It also forms the foundation of ES6 classes, which use prototypes under the hood. By mastering Object.create now, you'll understand the true engine behind JavaScript's object-oriented features and be prepared for advanced patterns like OLOO (Objects Linking to Other Objects).