DEV Community

Sai Swaroop Bijinapalli
Sai Swaroop Bijinapalli

Posted on

Prototypes in JS

JavaScript Prototypes Explained: A Complete Beginner's Guide

Introduction

If you've been learning JavaScript, you've probably heard the term prototype many times. At first, it can seem confusing because JavaScript doesn't use traditional class-based inheritance like Java or C++. Instead, JavaScript uses prototype-based inheritance.

Understanding prototypes is one of the biggest milestones in becoming a strong JavaScript developer. Once you understand how prototypes work, concepts like inheritance, constructor functions, classes, new, and object methods become much easier.

In this blog, we'll learn prototypes from scratch with simple explanations, diagrams, and practical examples.


What is a Prototype?

A prototype is simply another object from which an object inherits properties and methods.

Every JavaScript object has a hidden internal property called [[Prototype]]. In most browsers, you can access it using:

__proto__
Enter fullscreen mode Exit fullscreen mode

Whenever JavaScript cannot find a property or method inside an object, it automatically searches in its prototype.

This lookup process is called the Prototype Chain.


Think of it Like Real Life

Imagine a student asking questions.

Student
    ↓
Teacher
    ↓
Principal
Enter fullscreen mode Exit fullscreen mode

If the student doesn't know the answer, they ask the teacher.

If the teacher doesn't know, they ask the principal.

JavaScript behaves in the same way.

If an object doesn't contain a property, JavaScript checks its prototype. If it's still not found, JavaScript continues checking higher prototypes until it reaches null.


Your First Prototype Example

const person = {
    name: "Sai"
};

console.log(person.name);
Enter fullscreen mode Exit fullscreen mode

Output

Sai
Enter fullscreen mode Exit fullscreen mode

JavaScript finds name directly inside the object.

But now look at this:

console.log(person.toString());
Enter fullscreen mode Exit fullscreen mode

We never created a toString() method.

Why does it work?

Because JavaScript searches inside Object.prototype, where toString() already exists.

The lookup happens like this:

person
   ↓
Object.prototype
   ↓
null
Enter fullscreen mode Exit fullscreen mode

Every Object Has a Prototype

Let's inspect it.

const person = {
    name: "Sai"
};

console.log(person.__proto__);
Enter fullscreen mode Exit fullscreen mode

Output

Object.prototype
Enter fullscreen mode Exit fullscreen mode

We can even verify it.

console.log(person.__proto__ === Object.prototype);
Enter fullscreen mode Exit fullscreen mode

Output

true
Enter fullscreen mode Exit fullscreen mode

This proves that every ordinary object inherits from Object.prototype.


Object.prototype

Object.prototype is the root object for almost every JavaScript object.

It already contains useful methods such as:

  • toString()
  • hasOwnProperty()
  • valueOf()
  • isPrototypeOf()
  • propertyIsEnumerable()

Example:

const obj = {};

console.log(obj.hasOwnProperty("name"));
Enter fullscreen mode Exit fullscreen mode

Output

false
Enter fullscreen mode Exit fullscreen mode

Even though we never created hasOwnProperty(), it is inherited from Object.prototype.


Understanding the Prototype Chain

Consider two objects.

const animal = {
    eats: true
};

const dog = {
    barks: true
};

dog.__proto__ = animal;

console.log(dog.eats);
Enter fullscreen mode Exit fullscreen mode

Output

true
Enter fullscreen mode Exit fullscreen mode

How did JavaScript find eats?

Search process:

dog
│
└── eats? ❌

animal
│
└── eats? ✅
Enter fullscreen mode Exit fullscreen mode

Since JavaScript finds the property in the prototype, it returns true.


Visualizing the Prototype Chain

dog
{
    barks: true
}

        ↓

animal
{
    eats: true
}

        ↓

Object.prototype

        ↓

null
Enter fullscreen mode Exit fullscreen mode

Whenever a property is requested, JavaScript searches from top to bottom until it finds it.


Using Object.create()

Instead of manually changing __proto__, modern JavaScript recommends using Object.create().

const animal = {
    eats: true
};

const dog = Object.create(animal);

dog.barks = true;

console.log(dog.eats);
Enter fullscreen mode Exit fullscreen mode

Output

true
Enter fullscreen mode Exit fullscreen mode

Prototype relationship

dog
   ↓
animal
   ↓
Object.prototype
Enter fullscreen mode Exit fullscreen mode

Why Prototypes Save Memory

Suppose we create two users.

Without prototypes:

const user1 = {
    name: "Sai",

    greet() {
        console.log("Hello");
    }
};

const user2 = {
    name: "Ram",

    greet() {
        console.log("Hello");
    }
};
Enter fullscreen mode Exit fullscreen mode

Each object stores its own copy of greet().

This wastes memory.

Instead, create one shared object.

const userMethods = {
    greet() {
        console.log("Hello");
    }
};

const user1 = Object.create(userMethods);
user1.name = "Sai";

const user2 = Object.create(userMethods);
user2.name = "Ram";
Enter fullscreen mode Exit fullscreen mode

Now both objects share the same function.

user1
   ↓
userMethods
   ↑
user2
Enter fullscreen mode Exit fullscreen mode

Only one copy of greet() exists in memory.


Constructor Functions and Prototypes

Before ES6 classes, JavaScript commonly used constructor functions.

function Person(name) {
    this.name = name;
}
Enter fullscreen mode Exit fullscreen mode

Methods are added to the prototype.

Person.prototype.greet = function () {
    console.log("Hello " + this.name);
};
Enter fullscreen mode Exit fullscreen mode

Creating objects:

const p1 = new Person("Sai");
const p2 = new Person("Ram");

p1.greet();
p2.greet();
Enter fullscreen mode Exit fullscreen mode

Output

Hello Sai
Hello Ram
Enter fullscreen mode Exit fullscreen mode

Notice that both objects use the same greet() method.


What Happens When You Use new?

When you write:

const person = new Person("Sai");
Enter fullscreen mode Exit fullscreen mode

JavaScript performs four steps:

Step 1

Creates a new empty object.

{}
Enter fullscreen mode Exit fullscreen mode

Step 2

Connects it to Person.prototype.

new object
     ↓
Person.prototype
Enter fullscreen mode Exit fullscreen mode

Step 3

Calls the constructor.

Person.call(newObject, "Sai");
Enter fullscreen mode Exit fullscreen mode

Inside the constructor:

this.name = "Sai";
Enter fullscreen mode Exit fullscreen mode

becomes

newObject.name = "Sai";
Enter fullscreen mode Exit fullscreen mode

Step 4

Returns the new object.


ES6 Classes Still Use Prototypes

Modern JavaScript introduced classes.

class Person {

    constructor(name) {
        this.name = name;
    }

    greet() {
        console.log("Hello " + this.name);
    }

}
Enter fullscreen mode Exit fullscreen mode

Creating an object:

const person = new Person("Sai");

person.greet();
Enter fullscreen mode Exit fullscreen mode

Output

Hello Sai
Enter fullscreen mode Exit fullscreen mode

Although the syntax looks different, JavaScript internally stores greet() inside Person.prototype.

Classes are simply syntactic sugar over prototypes.


Property Shadowing

A child object can override properties from its prototype.

const animal = {
    legs: 4
};

const dog = Object.create(animal);

console.log(dog.legs);
Enter fullscreen mode Exit fullscreen mode

Output

4
Enter fullscreen mode Exit fullscreen mode

Override it.

dog.legs = 3;

console.log(dog.legs);
Enter fullscreen mode Exit fullscreen mode

Output

3
Enter fullscreen mode Exit fullscreen mode

Now JavaScript finds legs directly inside dog, so it doesn't continue searching.


Checking Where a Property Exists

const animal = {
    eats: true
};

const dog = Object.create(animal);

dog.name = "Tom";

console.log(dog.hasOwnProperty("name"));
Enter fullscreen mode Exit fullscreen mode

Output

true
Enter fullscreen mode Exit fullscreen mode

Now check another property.

console.log(dog.hasOwnProperty("eats"));
Enter fullscreen mode Exit fullscreen mode

Output

false
Enter fullscreen mode Exit fullscreen mode

The property exists through inheritance, not inside dog.


Complete Prototype Chain Example

const livingThing = {
    alive: true
};

const animal = Object.create(livingThing);
animal.eats = true;

const dog = Object.create(animal);
dog.barks = true;

console.log(dog.alive);
console.log(dog.eats);
console.log(dog.barks);
Enter fullscreen mode Exit fullscreen mode

Output

true
true
true
Enter fullscreen mode Exit fullscreen mode

Search order:

dog
   ↓
animal
   ↓
livingThing
   ↓
Object.prototype
   ↓
null
Enter fullscreen mode Exit fullscreen mode

Why Are Prototypes Important?

Prototypes provide several advantages:

  • Enable inheritance between objects.
  • Allow methods to be shared instead of duplicated.
  • Reduce memory consumption.
  • Improve application performance.
  • Form the foundation of JavaScript's object-oriented programming model.

Without prototypes, every object would need its own copy of every method.


Interview Questions

What is a prototype?

A prototype is an object from which another object inherits properties and methods.


What is the prototype chain?

The sequence of objects JavaScript searches when a property isn't found on the current object.


Why use Object.create()?

It creates a new object with a specified prototype and is the recommended alternative to modifying __proto__.


What is Object.prototype?

It is the root prototype for most JavaScript objects and contains built-in methods like toString() and hasOwnProperty().


Are ES6 classes different from prototypes?

No. Classes are simply cleaner syntax built on top of JavaScript's prototype system.


What does the new keyword do?

  • Creates a new object.
  • Links it to the constructor's prototype.
  • Executes the constructor with this pointing to the new object.
  • Returns the newly created object.

Key Takeaways

  • Every JavaScript object has a hidden prototype ([[Prototype]]).
  • JavaScript follows the prototype chain when searching for properties.
  • Most objects inherit from Object.prototype.
  • Object.create() is the preferred way to establish prototype inheritance.
  • Constructor functions share methods using .prototype.
  • ES6 classes are built on top of the prototype system.
  • Prototypes make JavaScript memory-efficient by allowing objects to share methods instead of creating duplicate copies.

Conclusion

Prototypes are one of JavaScript's most powerful features. While they may seem challenging initially, understanding them unlocks many advanced concepts such as constructor functions, inheritance, classes, and the new keyword.

The next time you call methods like toString() or hasOwnProperty(), remember that those methods aren't stored directly in your object—they come from the prototype chain.

Top comments (0)