How JavaScript Extends Keyword Works Internally

JavaScript class inheritance using the extends keyword provides a clean, declarative syntax for building object hierarchies, but it operates entirely on JavaScript’s existing prototypal inheritance model. Internally, extends establishes a dual prototype chain—linking both instance methods and static methods—while fundamentally altering how instance construction and the this binding are handled via super(). Understanding this internal mechanics demystifies how ES6 classes interact with the engine’s underlying prototype architecture.

The Dual Prototype Chain

When a child class extends a parent class, JavaScript creates two distinct prototype linkages under the hood:

  1. Instance Method Inheritance: The child’s prototype object inherits from the parent’s prototype object:

    Object.setPrototypeOf(Child.prototype, Parent.prototype);
    // Child.prototype.__proto__ === Parent.prototype

    This ensures that any method defined on Parent.prototype is accessible by instances of Child via standard prototype delegation.

  2. Static Method Inheritance: The child constructor function itself inherits from the parent constructor function:

    Object.setPrototypeOf(Child, Parent);
    // Child.__proto__ === Parent

    This allows static methods and properties declared on Parent to be directly accessible on Child without instantiating an object.

Constructor Execution and the this Binding

In standard JavaScript constructor functions, the JavaScript engine creates a new empty object, binds it to this, and then executes the constructor body. Derived classes (classes using extends) behave differently:

Internal Mechanics with Reflect.construct

The behavior of extends and super() can be conceptualized using the built-in Reflect.construct API introduced in ES6:

function Parent(name) {
  this.name = name;
}

function Child(name, role) {
  // Equivalent to super(name)
  const self = Reflect.construct(Parent, [name], Child);
  self.role = role;
  return self;
}

// Establish prototype linkages
Object.setPrototypeOf(Child.prototype, Parent.prototype);
Object.setPrototypeOf(Child, Parent);

In this flow: - Reflect.construct(Parent, [name], Child) invokes Parent to initialize the object, but sets the internal [[Prototype]] of the created object to Child.prototype. - The derived constructor receives the initialized object, modifies it, and returns it.

Method Resolution and super Property Access

When using super.method() inside a derived class method, the engine uses the internal slot [[HomeObject]].

Every method defined inside an ES6 class possesses a [[HomeObject]] reference that points to the class prototype where the method was defined. When super.method() is evaluated, the JavaScript engine looks up Object.getPrototypeOf([[HomeObject]]) to find the parent method and then executes it using the current this context via .call(this, ...args). This static binding guarantees that super references resolve correctly even when methods are detached or dynamically assigned.