Skip to content
Plurafy

Prototypes and Inheritance

Understanding prototype chain and object-oriented programming in JavaScript

You need to create a hierarchy of objects (Animal → Dog) where Dog inherits properties and methods from Animal. Why does modifying a prototype affect all instances?

JavaScript uses prototype-based inheritance instead of classical inheritance. Every object has a prototype, and objects inherit properties through the prototype chain.

function Animal(name) {
this.name = name;
}
// Add method to prototype (shared across instances)
Animal.prototype.speak = function() {
console.log(`${this.name} makes a sound`);
};
const dog = new Animal('Rex');
dog.speak(); // "Rex makes a sound"
console.log(dog.hasOwnProperty('speak')); // false - method is on prototype
console.log('speak' in dog); // true - found via prototype chain
function Animal(name) {
this.name = name;
}
Animal.prototype.type = 'Animal';
function Dog(name, breed) {
Animal.call(this, name); // Call parent constructor
this.breed = breed;
}
// Set up inheritance
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function() {
console.log('Woof!');
};
const myDog = new Dog('Buddy', 'Golden Retriever');
console.log(myDog.name); // "Buddy" - own property
console.log(myDog.breed); // "Golden Retriever" - own property
console.log(myDog.type); // "Animal" - inherited from Animal.prototype
myDog.bark(); // "Woof!"
// Prototype chain: myDog -> Dog.prototype -> Animal.prototype -> Object.prototype -> null
function Animal(name) {
this.name = name;
}
Animal.prototype.move = function() {};
function Dog(name) {
Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.bark = function() {};
const dog = new Dog('Max');
// Different ways to check
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
console.log(dog instanceof Object); // true
console.log(Dog.prototype.isPrototypeOf(dog)); // true
console.log(Animal.prototype.isPrototypeOf(dog)); // true
console.log(Object.getPrototypeOf(dog) === Dog.prototype); // true
// View entire chain
console.log(Object.getPrototypeOf(dog)); // Dog.prototype
console.log(Object.getPrototypeOf(Object.getPrototypeOf(dog))); // Animal.prototype
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Object.getPrototypeOf(dog)))); // Object.prototype
// ES6 classes are syntactic sugar over prototypes
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a sound`);
}
}
class Dog extends Animal {
constructor(name, breed) {
super(name); // Call parent constructor
this.breed = breed;
}
speak() {
super.speak(); // Call parent method
console.log('Woof!');
}
bark() {
console.log('Bark bark bark!');
}
}
const dog = new Dog('Rex', 'Labrador');
dog.speak(); // "Rex makes a sound" \n "Woof!"
dog.bark(); // "Bark bark bark!"
function Person() {
this.age = 30;
}
Person.prototype.name = 'Generic Person';
Person.prototype.work = function() {};
const john = new Person();
john.name = 'John'; // Own property shadows prototype
console.log(john.name); // "John" - found on john itself first
console.log(john.age); // 30 - found on john
console.log(john.walk); // undefined - not in chain
delete john.name; // Remove own property
console.log(john.name); // "Generic Person" - now looks up to prototype
for (let key in john) {
console.log(key); // age, name, work - includes inherited properties
}
for (let key of Object.keys(john)) {
console.log(key); // age - only own properties
}
// ⚠️ Problem: Shared mutable reference on prototype
function Config() {}
Config.prototype.settings = []; // Shared array!
const config1 = new Config();
const config2 = new Config();
config1.settings.push('setting1');
console.log(config2.settings); // ['setting1'] - ❌ Unexpected!
// ✅ Solution: Use constructor for mutable objects
function GoodConfig() {
this.settings = []; // Each instance gets own array
}
const goodConfig1 = new GoodConfig();
const goodConfig2 = new GoodConfig();
goodConfig1.settings.push('setting1');
console.log(goodConfig2.settings); // [] - ✅ Isolated

Interview Tip: instanceof and Type Checking

Section titled “Interview Tip: instanceof and Type Checking”
class Animal {}
class Dog extends Animal {}
const dog = new Dog();
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
// Safer: check for constructor
console.log(dog.constructor === Dog); // true
// Safest: use Symbol.toStringTag or duck typing
console.log(Object.prototype.toString.call(dog)); // [object Object]