Understanding JavaScript Prototypes: How Inheritance Works

posted Originally published at thefrontendarchitect.com 3 min read

Why You Should Understand Prototypes

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`)

Explanation

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

The Prototype Chain in JavaScript

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)

Diagram

student → person → Object.prototype → null

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

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

__proto__ vs prototype : What’s the Difference?

This is a common confusion for new developers.

__proto__ The internal prototype of an instance

prototype A property on constructor functions used to create new 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__ points to Animal.prototype, where speak() is defined.

ES6 Classes & Prototypes

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

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

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

Even with class, JavaScript uses prototypes behind the scenes.

Why Use Prototypes?

Using prototypes provides several advantages:

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

Anti-pattern Example

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 separate function. That’s inefficient.

Recommended Prototype Approach

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

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

console.log(u1.sayHi === u2.sayHi); // true 

Common Pitfalls When Using Prototypes

Avoid these mistakes when working with prototypes:

  • Don’t manually set __proto__ — use Object.create() or a proper constructor
  • Don’t overuse inheritance — favor composition where possible
  • Prototype chain lookups are slower than direct property access

Helpful Built-in Methods for Working with Prototypes

Object.create(proto)Creates a new object with a given prototype

Object.getPrototypeOf(obj)Returns the prototype of obj

Object.setPrototypeOf(obj, proto)Sets the prototype (avoid for performance reasons)

instanceofChecks if proto exists in the object’s prototype chain

hasOwnProperty()Checks if the property exists on the object itself, not its prototype

Debugging Prototype Issues

Use DevTools in your browser to inspect prototype chains.

Try these in the console:

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

Conclusion

Understanding how JavaScript handles prototypes gives you the power to write clean, reusable, and performant code.

Key Takeaways

  • Every object in JS has a prototype, forming a chain
  • Inheritance flows up the prototype chain
  • Constructor functions and class use prototypes
  • Prototypes help reduce memory usage and improve structure
  • Don’t manually tinker with __proto__ — use proper patterns

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

If you read this far, tweet to the author to show them you care. Tweet a Thanks

Great breakdown of prototypes! Understanding the prototype chain really changes how you think about inheritance in JavaScript. Have you found any common mistakes or misconceptions among devs when transitioning from classical OOP to JavaScript’s prototype-based inheritance? Would love to hear your thoughts!

Based on my personal experience and the teams I've worked with, the approach can vary significantly from project to project. A lot of it depends on the developer's level of seniority. For example, mid-level to senior developers usually have a deeper understanding of these concepts.

Personally, I’m comfortable using inheritance when needed, but I prefer composition. With composition, you build complex behavior by combining simple, independent functions or objects.

Here's how it works:

const canBark = () => ({
bark: () => console.log("Barks"),
});

const canRun = () => ({
run: () => console.log("Runs"),
});

const createDog = (name) => {
return {

name,
...canBark(),
...canRun(),

};
};

const dog = createDog("Rex");
dog.bark(); // Barks
dog.run(); // Runs

More Posts

Still.js - A way to leverage Vanilla JavaScript for Complex and Enterprise Level Web Development

Nakassony Bernardo - Jun 29

The Unchaining: My Personal Journey Graduating from jQuery to Modern JavaScript

kitfu10 - May 20

JavaScript: Understanding the Set and Clear Interval Methods

Michael Larocca - Jun 25

Understanding Obfuscation In Javascript

Dhanush Nehru - Jan 12

Understanding "this" in JavaScript objects and functions.

Temi_lolu - Nov 30, 2024
chevron_left