Understanding Prototypes in JavaScript

When you start learning JavaScript, you’ll often hear this phrase:

“In JavaScript, everything is an object.”

But what’s often left out is how JavaScript handles inheritance — not through classes (traditionally), but through prototypes.

In this post, we’ll explore:

  • What prototypes are
  • How the prototype chain works
  • __proto__ vs prototype
  • How JavaScript uses prototypes for inheritance
  • How ES6 classes relate to prototypes
  • When and why you should care

What Is a Prototype?

In JavaScript, every object has an internal link to another object called its prototype.

This prototype object can have its own prototype, forming a prototype chain. The chain ends when a prototype is null.

Think of it like a fallback mechanism: if a property or method isn’t found on an object, JavaScript looks up the chain.

Example:

const person = {
  greet() {
    return "Hello!";
  }
};

const student = Object.create(person);
student.name = "Toni";

console.log(student.name);      // "Toni"
console.log(student.greet());  // "Hello!" (inherited from `person`)

Here:

  • student doesn’t have greet().
  • JavaScript looks up the prototype chain (to person) and finds it there.

The Prototype Chain

Every object in JavaScript has a hidden property [[Prototype]] (accessible via __proto__) that points to its prototype.

const obj = {};
console.log(obj.__proto__);             // Same as Object.prototype
console.log(obj.__proto__.__proto__);  // null (end of chain)

Diagrammatically:

student --> person --> Object.prototype --> null

When you access student.greet(), JS will:

  1. Look for greet in student.
  2. Not found? Check student.__proto__ (which is person).
  3. Still not found? Go up again (to Object.prototype).
  4. If nowhere to be found → undefined.

Function Prototypes vs Object Prototypes

This often confuses people: there’s a difference between prototype and __proto__.

  • __proto__: Property of the object instance. Points to its prototype.
  • prototype: Property of the constructor function. Used to set the __proto__ of instances.

Example with Constructor:

function Animal(name) {
  this.name = name;
}

Animal.prototype.speak = function () {
  return `${this.name} makes a noise.`;
};

const dog = new Animal("Rex");
console.log(dog.speak()); // "Rex makes a noise."

console.log(dog.__proto__ === Animal.prototype); // true
  • dog.__proto__ is the prototype from which it inherits — in this case, Animal.prototype.
  • Animal.prototype.speak is shared among all instances.

ES6 Classes & Prototypes

ES6 introduced the class syntax, but it’s syntactic sugar over the same prototypal system.

class Vehicle {
  drive() {
    console.log("Vroom!");
  }
}

const car = new Vehicle();
car.drive(); // "Vroom!"

console.log(Object.getPrototypeOf(car) === Vehicle.prototype); // true

So even with class, JavaScript still uses prototypes underneath.

Why Use Prototypes?

Using prototypes helps with:

  • Memory efficiency — methods are shared across instances.
  • Performance — avoids recreating functions for every object.
  • Structure — clear inheritance paths.

Imagine this mistake:

function User() {
  this.sayHi = function () {
    console.log("Hi!");
  };
}

const u1 = new User();
const u2 = new User();

console.log(u1.sayHi === u2.sayHi); // false 😢

Each sayHi is a new function. Instead:

User.prototype.sayHi = function () {
  console.log("Hi!");
};

Now all instances share the same method.

Common Pitfalls

  • Don’t manually set __proto__ — use Object.create() or proper inheritance.
  • Avoid overusing inheritance. Favor composition over inheritance when possible.
  • Prototype chain lookups can be slower than direct access.

Recap

  • Every object in JS has a prototype, which forms a chain.
  • Prototypes allow for method and property inheritance.
  • Constructor functions and ES6 classes use prototype to define shared behavior.
  • Understanding the prototype system helps you write cleaner, more performant code.

Helpful Methods

MethodDescription
Object.create(proto)Creates a new object with the specified prototype
Object.getPrototypeOf(obj)Returns the prototype of the object
Object.setPrototypeOf(obj, proto)Sets the prototype (not recommended for performance)
instanceofChecks prototype chain
hasOwnProperty()Checks if a property exists directly on the object, not via prototype

Prototype Debugging Tips

Use browser DevTools! Console commands like these are your friends:

Object.getPrototypeOf(obj)
obj.hasOwnProperty('prop')
console.dir(obj)

If you’re still thinking in classes, you’re missing out on JavaScript’s true inheritance model.

Share this content:

Hi, my name is Toni Naumoski, and I’m a Senior Frontend Developer with a passion for blending code and design. With years of experience as a Frontend Developer, Web Designer, and Creative Technologist, I specialize in crafting unique, responsive, and detail-oriented websites and web applications that stand out. I bring deep expertise in HTML, CSS, and JavaScript—working fluently with modern frameworks like React, Angular, and Vue, as well as animation libraries like GSAP. My creative side thrives in Photoshop and Figma, and I enjoy extending functionality using tools like Express.js and ChatGPT. My work is guided by high integrity, strong communication, a positive attitude, and a commitment to being a reliable collaborator. I take pride in delivering high-quality digital experiences that are both technically solid and visually compelling.

Post Comment