Prototypes and Prototype Chain in JavaScript

Prototypes and Prototype Chain in JavaScript

Description
The prototype is the mechanism for implementing inheritance in JavaScript. Every object has a hidden property [[Prototype]] (accessible via __proto__ or Object.getPrototypeOf()), which points to its prototype object. The prototype object itself also has a prototype, forming a chain-like structure known as the prototype chain. When accessing a property of an object, if the property does not exist on the object itself, the search proceeds up the prototype chain until the property is found or the end of the chain (null) is reached.

Detailed Explanation

  1. Prototype Object

    • Every function automatically receives a prototype property when created, which points to a prototype object.
    • When a function is called as a constructor with new, the newly created instance's [[Prototype]] will point to that function's prototype.
      Example:
    function Person(name) {
      this.name = name;
    }
    // Add a method to the prototype object
    Person.prototype.sayHello = function() {
      console.log(`Hello, I'm ${this.name}`);
    };
    const alice = new Person("Alice");
    alice.sayHello(); // Output: Hello, I'm Alice
    
    • alice does not have its own sayHello method but finds it on Person.prototype via [[Prototype]].
  2. Formation of the Prototype Chain

    • The prototype object itself is also an object, so it has a [[Prototype]]. For example, the [[Prototype]] of Person.prototype points to Object.prototype.
    • The top of the chain is Object.prototype, whose [[Prototype]] is null.
      Example:
    console.log(alice.__proto__ === Person.prototype); // true
    console.log(alice.__proto__.__proto__ === Object.prototype); // true
    console.log(alice.__proto__.__proto__.__proto__); // null
    
    • When looking up a property, the order is: alicePerson.prototypeObject.prototypenull.
  3. Property Shadowing and Overwriting

    • If an object has its own property, it will not look up the prototype chain (the property is "shadowed").
    • Direct assignment only modifies the object's own property and does not affect properties on the prototype chain.
      Example:
    alice.sayHello = function() {
      console.log("Hola!");
    };
    alice.sayHello(); // Output: Hola! (accesses own property)
    const bob = new Person("Bob");
    bob.sayHello(); // Output: Hello, I'm Bob (still accesses the method on the prototype)
    
  4. Prototype Chain and Inheritance

    • Inheritance can be achieved by setting the child class's prototype to an instance of the parent class:
    function Student(name, grade) {
      Person.call(this, name); // Call the parent constructor
      this.grade = grade;
    }
    Student.prototype = Object.create(Person.prototype); // Inherit the prototype
    Student.prototype.constructor = Student; // Fix constructor reference
    Student.prototype.study = function() {
      console.log(`${this.name} is studying.`);
    };
    const charlie = new Student("Charlie", 5);
    charlie.sayHello(); // Inherited from Person.prototype
    
    • The prototype chain is now: charlieStudent.prototype (i.e., an instance of Person) → Person.prototypeObject.prototype.

Summary
The prototype chain is a core feature of JavaScript, enabling property and method sharing through the [[Prototype]] links of objects. Understanding the prototype chain is essential for mastering inheritance, property lookup mechanisms, and avoiding common property shadowing issues.