Objects and Prototypes
Objectives
By the end of this chapter, you should be able to:
- Explain that every object has a hidden link to another object called its prototype
- Share methods between objects with
Object.create()and a shared prototype object - Recognize the constructor function plus
.prototypepattern thatclassis built on - Predict where JavaScript looks when you call a method that isn’t on the object itself
💡 Why this matters: The
classkeyword you’ll learn in the next lesson looks like a brand new feature, but it isn’t. It’s a cleaner way to write something JavaScript has always done with plain objects and prototypes. Seeing the raw mechanism first makesclassfeel like syntax, not magic.
Objects Already Borrow Methods
You’ve been using objects since Module 5, but you’ve also been calling methods that were never defined on them.
const priya = { name: "Priya" };
console.log(priya.toString());
// [object Object]
priya only has one property: name. Nobody wrote a toString method on it. So where did toString come from?
console.log(Object.getPrototypeOf(priya) === Object.prototype);
// true
Every plain object has a hidden link to another object, called its prototype. When you call priya.toString(), JavaScript looks for toString on priya first, doesn’t find it, then checks priya’s prototype, and finds it there. This lookup is called the prototype chain. You don’t need to memorize its full depth, just the idea: if a property or method isn’t found on an object, JavaScript checks the object’s prototype next.
Sharing Methods with Object.create()
You can use this same mechanism yourself, so multiple objects share one copy of a method instead of each having its own.
const dogPrototype = {
bark() {
return `${this.name} says woof!`;
}
};
function makeDog(name) {
const dog = Object.create(dogPrototype);
dog.name = name;
return dog;
}
const rex = makeDog("Rex");
const buddy = makeDog("Buddy");
console.log(rex.bark());
// Rex says woof!
console.log(buddy.bark());
// Buddy says woof!
makeDog is a factory function: it builds and returns a new object instead of using new. Object.create(dogPrototype) creates a fresh object whose prototype is dogPrototype. rex and buddy each get their own name, but they share the exact same bark function underneath.
console.log(Object.getPrototypeOf(rex) === dogPrototype);
// true
console.log(rex.bark === buddy.bark);
// true
console.log(rex.hasOwnProperty("bark"));
// false
rex.bark === buddy.bark is true because there’s only one bark function in memory, sitting on dogPrototype, and both dogs reach it through the prototype link. rex.hasOwnProperty("bark") is false because bark isn’t rex’s own property, it’s inherited.
Constructor Functions: The Bridge to class
There’s an older, more common pattern for the same idea, using a regular function together with new and .prototype.
function Dog(name) {
this.name = name;
}
Dog.prototype.bark = function () {
return `${this.name} says woof!`;
};
const rex = new Dog("Rex");
console.log(rex.bark());
// Rex says woof!
console.log(rex instanceof Dog);
// true
console.log(Object.getPrototypeOf(rex) === Dog.prototype);
// true
new Dog("Rex") creates a new object, links its prototype to Dog.prototype, runs Dog with this set to that new object, and returns it. That’s the constructor-call rule from the last lesson: this inside Dog is the object new just built, which is why this.name = name ends up on rex. Dog.prototype.bark works exactly like dogPrototype.bark did above: one shared function, reached through the prototype link.
This constructor-function-plus-.prototype pattern is exactly what the class keyword is built on. When you write class Dog { constructor(name) {...} bark() {...} } in the next lesson, JavaScript is doing the same thing you just did by hand: a function to build the object, and methods living on a shared prototype.
Try It
- Create a
catPrototypeobject with ameow()method that returns"${this.name} says meow!". Write amakeCat(name)factory function usingObject.create(), make two cats, and confirm both share the samemeowfunction with===. - Rewrite the
Dogexample as a constructor function calledCar, with ahonk()method onCar.prototypethat returns"${this.model} goes beep!". Create two cars with differentmodelvalues and callhonk()on each. - For any object you create in this lesson, log
Object.getPrototypeOf(yourObject)and check it matches the prototype object you expected.
Recap
- Every object has a hidden link to another object, its prototype, and JavaScript checks that link when a method isn’t found directly on the object.
Object.create(someProto)creates an object whose prototype issomeProto, so objects can share methods without duplicating them.- A constructor function combined with
.prototypeandnewdoes the same thing, and it’s the direct ancestor of theclasssyntax. - None of this is a deep dive into the whole prototype chain, just enough to see that classes aren’t magic.
Next lesson: the class keyword, constructors, and static methods, and how they map directly onto what you just built by hand.