JavaScript Prototype Chain and Inheritance

Understanding JavaScript's prototype-based inheritance system

By Hank Kim

JavaScript Prototype Chain and Inheritance

Understanding JavaScript's prototype-based inheritance system

JavaScript Prototype Chain and Inheritance

1. Prototypes in JavaScript

Definition

  • In JavaScript, every object has an internal link to another object called its prototype.
  • Properties and methods defined on the prototype are shared across all instances created from the same constructor.
  • This mechanism enables prototype-based inheritance.

Function Constructors and prototype

  • Functions in JavaScript are special objects.

  • Every function has a prototype property by default.

  • When used with the new operator, this prototype object becomes the prototype of the newly created instance.

  • Example:

    function Person(name) {
      this.name = name;
    }
    
    Person.prototype.sayHello = function () {
      console.log(`Hi, I'm ${this.name}`);
    };
    
    const hank = new Person("Hank");
    hank.sayHello(); // "Hi, I'm Hank"
    
  • Here, sayHello is not copied to each instance; instead, instances reference Person.prototype through their internal __proto__.


The new Operator

When a function is called with new, the following steps happen:

  1. A new empty object is created.
  2. The object’s internal __proto__ is set to the function’s prototype.
  3. The constructor function is executed, binding this to the new object.
  4. If no other object is explicitly returned, the new object is returned.
function Person(name) {
  this.name = name;
}

const p1 = Person("Hank"); // Without `new`
// `this` refers to global object → global.name = "Hank"
console.log(p1); // undefined

const p2 = new Person("Hank"); // With `new`
// A new Person object is created
console.log(p2); // Person { name: "Hank" }

Prototype Chain

  • If a property is not found on an object, JavaScript follows the __proto__ link to search its prototype.

  • This continues up the chain until it reaches Object.prototype, the root of all objects.

  • Example:

    function Person(name) {
      this.name = name;
    }
    Person.prototype.lastname = "Kim";
    
    const hank = new Person("Hank");
    console.log(hank.lastname); // "Kim"
    
    • The property lastname is not defined directly on hank.
    • The engine looks into hank.__proto__ → finds it in Person.prototype.
  • Built-in objects also rely on prototypes:

    const arr = [3, 1, 2];
    arr.sort(); // Works because Array.prototype defines sort()
    

Extending Prototypes

  • Developers can extend native prototypes to add custom behavior:

    Array.prototype.myMethod = function () {
      return "Custom method for all arrays!";
    };
    
    const arr = [1, 2, 3];
    console.log(arr.myMethod()); // "Custom method for all arrays!"
    
  • Caution: modifying built-in prototypes can cause conflicts and is discouraged in production.


ES6 Classes and Prototypes

  • Classes (introduced in ES6) are syntactic sugar over prototype-based inheritance.
  • Class methods are placed on the constructor’s prototype just like with function constructors.
  • Example:

    class Person {
      constructor(name) {
        this.name = name;
      }
      sayHello() {
        console.log(`Hi, I'm ${this.name}`);
      }
    }
    
    console.log(Person.prototype);
    // { constructor: ƒ Person, sayHello: ƒ }
    

2. Functions and Objects in JavaScript

Primitive Types vs Objects

  • Primitive types: string, number, boolean, null, undefined, symbol.
  • Everything else is an object: arrays, functions, maps, sets, etc.

Arrays Are Objects

  • Arrays are special objects with integer-like keys and a length property:

    const arr = [1, 2, 3];
    console.log(typeof arr); // "object"
    console.log(arr.length); // 3
    console.log(arr[0]); // 1
    
  • Internally similar to:

    { "0": 1, "1": 2, "2": 3, length: 3 }
    
  • Arrays are iterable because they implement the iterator protocol.


Functions Are Objects

  • Functions are callable objects:

    • They are objects and can have properties.
    • They also have an internal [[Call]] slot that makes them executable.
    function sayHello() {
      console.log("hi");
    }
    
    console.log(typeof sayHello); // "function"
    sayHello.foo = 123;
    console.log(sayHello.foo); // 123
    
  • Functions are treated specially by typeof (returns "function") but are still objects under the hood.


3. Summary

  • Prototype: Objects inherit from other objects through the prototype chain. Function constructors define methods on their prototype, shared across instances.
  • new operator: Automates object creation, prototype linkage, and this binding.
  • Prototype chain: Property lookup walks up __proto__ until Object.prototype.
  • Classes: Syntax sugar for prototype-based inheritance, not a new mechanism.
  • Everything but primitives is an object: Arrays and functions are just special types of objects.
  • Functions are objects: Can hold properties like objects, but also executable due to [[Call]].

Tags: JavaScript