Understanding Prototype Objects and the Prototype Chain in JavaScript

In JavaScript, every function has a prototype property, and every object (except null) is linked to another object known as its prototype. This linkage forms the basis of property inheritance through delegation rather than copying.

function Person() {}
Person.prototype.name = 'Kevin';
const person1 = new Person();
const person2 = new Person();
console.log(person1.name); // Kevin
console.log(person2.name); // Kevin

The prototype of a constructor function can be accessed via Constructor.prototype. Instances created from that constructor link to this prototype through their internal [[Prototype]], exposed in most environments as __proto__:

function Person() {}
const person = new Person();
console.log(person.__proto__ === Person.prototype); // true

Each prototype object also holds a constructor property pointing back to its associated constructor:

function Person() {}
console.log(Person === Person.prototype.constructor); // true

There are three standard ways to access an object’s prototype:

  1. Constructor.prototype
  2. instance.__proto__
  3. Object.getPrototypeOf(instance)

When accessing a property, JavaScript first checks the object itself. If the property isn’t found, it traverses up the prototype chain until it either finds the property or reaches the end (null), returning undefined if not found:

function Person() {}
Person.prototype.name = 'Kevin';
const person = new Person();
person.name = 'Daisy';
console.log(person.name); // Daisy

delete person.name;
console.log(person.name); // Kevin

At the top of the prototype chain lies Object.prototype, whose __proto__ is null:

console.log(Object.prototype.__proto__ === null); // true

JavaScript uses delegation: objects access properties from their prototypes without copying them.

Prototype Inspection Methods

Object.getPrototypeOf(obj) returns the prototype of obj:

function F() {}
const f = new F();
console.log(Object.getPrototypeOf(f) === F.prototype); // true
console.log(Object.getPrototypeOf(f) === f.__proto__);  // true

prototype.isPrototypeOf(obj) checks if the prototype exists in obj’s chain:

function Demo() {}
const demo = new Demo();
console.log(Demo.prototype.isPrototypeOf(demo));   // true
console.log(Object.prototype.isPrototypeOf(demo)); // true

instanceof tests whether a constructor’s prototype appears in the instance’s prototype chain:

function Demo() {}
const demo = new Demo();
console.log(demo instanceof Demo);   // true
console.log(demo instanceof Object); // true

console.log(Function instanceof Object); // true
console.log(Object instanceof Function); // true

Note: instanceof does not check how an object was created—it checks prototype chain membership. Changing a constructor’s prototype after creating an instance breaks the instanceof relationship:

function Person() {}
const p1 = new Person();
console.log(p1 instanceof Person); // true

Person.prototype = { constructor: Person };
console.log(p1 instanceof Person); // false

const p2 = new Person();
console.log(p2 instanceof Person); // true

Inheritance Patterns

Prototype-based inheritance directly assigns one prototype to another:

function Super() {}
Super.prototype.info = 'Super info';

function Sub() {}
Sub.prototype = Super.prototype;
Sub.prototype.constructor = Sub;

const s = new Sub();
console.log(s.info); // Super info

Prototype chain inheritance sets the parent’s instance as the child’s prototype:

function Super() {
  this.name = 'Super name';
}
Super.prototype.info = 'Super info';

function Sub() {}
Sub.prototype = new Super();
Sub.prototype.constructor = Sub;

const s = new Sub();
console.log(s.name); // Super name
console.log(s.info); // Super info

This approach doesn’t support passing arguemnts to the parent constructor during child instantiation.

Combination inheritance merges constructor stealing with prototype chaining to inherit both instance and prototype properties while enabling parameter passing:

function Super(name) {
  this.name = name;
}
Super.prototype.info = 'Super info';

function Sub(name) {
  Super.call(this, name); // inherit instance properties
}
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;

const s1 = new Sub('Alice');
const s2 = new Sub('Bob');
console.log(s1.name, s2.name); // Alice Bob
console.log(s1.info);          // Super info

Tags: javascript Prototypes prototype chain Inheritance Object-Oriented Programming

Posted on Fri, 12 Jun 2026 16:17:06 +0000 by eddierosenthal