CodingNic

Object-Oriented Programming

Objects and Prototypes

Object-Oriented Programming 20 min read

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 .prototype pattern that class is built on
  • Predict where JavaScript looks when you call a method that isn’t on the object itself

💡 Why this matters: The class keyword 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 makes class feel 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.

javascript
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?

javascript
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.

javascript
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.

javascript
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.

javascript
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

  1. Create a catPrototype object with a meow() method that returns "${this.name} says meow!". Write a makeCat(name) factory function using Object.create(), make two cats, and confirm both share the same meow function with ===.
  2. Rewrite the Dog example as a constructor function called Car, with a honk() method on Car.prototype that returns "${this.model} goes beep!". Create two cars with different model values and call honk() on each.
  3. 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 is someProto, so objects can share methods without duplicating them.
  • A constructor function combined with .prototype and new does the same thing, and it’s the direct ancestor of the class syntax.
  • 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.