Episode 11 of 11

Prototype Inheritance

Implement inheritance using prototypes — understand how JavaScript class inheritance works under the hood with the prototype chain.

Prototype Inheritance

When you use extends in ES6, JavaScript sets up prototype inheritance behind the scenes. Let us see how inheritance works at the prototype level.

Inheritance with Constructor Functions

function User(name, email) {
    this.name = name;
    this.email = email;
}

User.prototype.login = function() {
    console.log(this.name + ' logged in');
    return this;
};

User.prototype.logout = function() {
    console.log(this.name + ' logged out');
    return this;
};

function Admin(name, email, role) {
    User.call(this, name, email);  // Call parent constructor
    this.role = role;
}

// Set up prototype inheritance:
Admin.prototype = Object.create(User.prototype);

// Add Admin-specific methods:
Admin.prototype.deleteUser = function(user) {
    console.log(user.name + ' deleted by ' + this.name);
};

How It Works

// Object.create(User.prototype) creates a new object whose __proto__ is User.prototype
// Setting Admin.prototype to this object links the prototype chains:

admin (instance)
  └── __proto__ → Admin.prototype
                    ├── deleteUser()
                    └── __proto__ → User.prototype
                                      ├── login()
                                      ├── logout()
                                      └── __proto__ → Object.prototype

Using the Inherited Class

var admin = new Admin('Shaun', 'shaun@example.com', 'super-admin');

admin.login();        // 'Shaun logged in'     (from User.prototype)
admin.deleteUser({}); // works                 (from Admin.prototype)

console.log(admin instanceof Admin);  // true
console.log(admin instanceof User);   // true

ES6 Class Equivalent

// All of the above is equivalent to:
class User {
    constructor(name, email) {
        this.name = name;
        this.email = email;
    }
    login() {
        console.log(this.name + ' logged in');
    }
}

class Admin extends User {
    constructor(name, email, role) {
        super(name, email);
        this.role = role;
    }
    deleteUser(user) {
        console.log(user.name + ' deleted');
    }
}

// The class syntax does all the prototype wiring for you

Comparison

TaskPrototype WayClass Way
Parent constructorUser.call(this, ...)super(...)
Inherit methodsAdmin.prototype = Object.create(User.prototype)extends User
Add methodsAdmin.prototype.method = function() {}method() {}

Series Summary

You now understand JavaScript OOP from both sides:

  • ES6 classes — the clean, modern syntax for OOP
  • Prototypes — the underlying mechanism that makes it all work

Key Takeaways

  • Object.create() creates an object with a specific prototype link
  • User.call(this, args) is the prototype equivalent of super(args)
  • ES6 extends sets up the same prototype chain automatically
  • Understanding prototypes helps you debug inheritance issues and understand JavaScript deeply