SECTION 1
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.
1986 • Self Language Created
1995 • JavaScript Is Born
2006 • Douglas Crockford Advocates Object.create
2009 • ECMAScript 5 Ships Object.create
Object.create() becomes an official part of the language, giving developers a clean, explicit way to set up prototype chains.2015 • ES6 Classes Arrive
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.
SECTION 2
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.KEY TAKEAWAY
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.SECTION 3
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.
SECTION 4
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.
BASIC SYNTAX
prototypeObject — any existing object (or 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:
COMMON 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.
SECTION 5
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 |
Comparison of JavaScript object creation methods
SECTION 6
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.
Creating a Car from a Vehicle Prototype
- 1
Step 1 — Define the Prototype Object
We start by creating a plain object calledvehiclethat 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; } };vehiclehaswheels,start(), anddescribe() - 2
Step 2 — Create a New Object with Object.create
Now we callObject.create(vehicle)to make a new object whose prototype isvehicle. At this point,caris an empty object.const car = Object.create(vehicle);car→ empty, prototype →vehicle - 3
Step 3 — Add Own Properties
We givecarits own unique data. These properties belong only tocarand won't affectvehicle.car.make = "Toyota"; car.model = "Camry"; car.year = 2024;carnow ownsmake,model,year - 4
Step 4 — Test Inherited Methods
Callingcar.start()works even thoughcardoesn't have its ownstartmethod. JavaScript delegates up the prototype chain tovehicle.car.start(); // "Engine started!""Engine started!" — inherited fromvehicle - 5
Step 5 — Test describe() with 'this'
Here's the cool part:car.describe()callsvehicle.describe(), butthisinside the method refers tocar, notvehicle. So it readscar.makeandcar.model.car.describe(); // "Toyota Camry""Toyota Camry" —thisbinds to the calling object
Why 'this' Matters
describe() 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.SECTION 7
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. |
Strengths and limitations of Object.create
KEY TAKEAWAY
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.SECTION 8
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 |
Object.create vs. ES6 classes
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.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
Object.create(someObj), does the new object receive copies of someObj's properties? Explain what actually happens.Show answer
Object.create does not copy any properties. It creates a brand-new, empty object and sets its internal [[Prototype]] link to point to someObj. When you access a property on the new object that it doesn't own, JavaScript follows this live link and looks it up on someObj. This is called delegation. Because the link is live, if someObj changes later, the new object will see those changes.Question 2: BASIC CALCULATION
puppy.sound return? Explain your reasoning.
const pet = { sound: "generic noise", legs: 4 };
const puppy = Object.create(pet);
puppy.sound = "woof";Show answer
puppy.sound returns "woof". Although pet has sound: "generic noise", line 3 assigns "woof" as an own property directly on puppy. This is property shadowing — the own property hides the inherited one. JavaScript finds sound on puppy immediately and never needs to check the prototype.Question 3: INTERMEDIATE
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());Show answer
"I have 3 sides.", "I have 4 sides.", and "I have 0 sides.". Both triangle and square inherit describe() from shape, but this inside the method refers to whichever object called it. So triangle.describe() reads triangle.sides (3), square.describe() reads square.sides (4), and shape.describe() reads shape.sides (0).Question 4: APPLIED
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)?Show answer
const character = { health: 100, takeDamage(amount) { this.health -= amount; } }; then const warrior = Object.create(character); warrior.name = "Aria"; warrior.weapon = "sword";. After calling warrior.takeDamage(25), warrior.health is 75. Here's an important detail: the first time this.health -= amount runs, this is warrior. The assignment creates a new own property health on warrior (initialized by reading 100 from the prototype, then subtracting 25). The prototype's character.health remains 100.Question 5: CRITICAL THINKING
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.Show answer
Object.create gives you direct, transparent control over the prototype chain. One scenario where it's better: if you want to create an object with null as its prototype (a truly "clean" dictionary with no inherited properties like toString), you can only do that with Object.create(null). Additionally, understanding Object.create is essential for debugging — when a class hierarchy behaves unexpectedly, knowing how prototype delegation works lets you trace the issue.SUMMARY
Lesson Summary
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).