*
Previous Classes-ES6-Javascript Encapsulation Next

JavaScript Prototypes and Inheritance

๐Ÿงฌ JavaScript Prototypes and Inheritance

JavaScript, unlike traditional object-oriented languages that use a class-based inheritance model, uses a prototype-based model.

๐Ÿ“˜ Prototypes

A prototype is a blueprint-like object that other objects can inherit properties and methods from.

  • Internal link: Every object in JavaScript has a special, internal Prototype property, which is a link to another object.
  • Property lookup: When you try to access a property or method on an object, JavaScript first looks for it on the object itself. If it's not found, it looks at the object's Prototype . This process continues up the prototype chain until the property is found or the end of the chain (null) is reached.

๐Ÿ”ง Example: Using Constructor Functions

This is the pre-ES6 method for creating objects and setting prototypes.

// A constructor function to create a base object
function Animal(name) {
  this.name = name;
}

// Add a method to the `Animal` prototype that will be shared by all instances
Animal.prototype.speak = function() {
  console.log(`${this.name} makes a noise.`);
};

// Create a new object instance
const dog = new Animal("Rex");

// Call the method, which is found on the prototype
dog.speak(); // Output: Rex makes a noise.

This shows that dog itself does not have a speak method, but it is available via the prototype chain.

๐Ÿ› ๏ธ Example: Using Object.create()

This is a more direct way to create a new object with a specified prototype.

const animalPrototype = {
  speak() {
    console.log(`${this.name} makes a noise.`);
  }
};

const dog = Object.create(animalPrototype);
dog.name = "Rex";

dog.speak(); // Output: Rex makes a noise.

๐Ÿ”— Inheritance

Inheritance is the process of creating a new object that acquires the properties and methods of an existing object. In JavaScript, this is achieved through the prototype chain.

๐Ÿงต The Prototype Chain

When an object inherits from another, it becomes a link in the prototype chain. The end of every prototype chain is Object.prototype, which in turn has a prototype of null. This is why all objects in JavaScript implicitly inherit methods like toString().

โœจ Example: extends and super() with ES6 Classes

ES6 classes provide a modern, cleaner syntax for achieving prototypal inheritance.

// Parent class
class Animal {
  constructor(name) {
    this.name = name;
  }
  speak() {
    console.log(`${this.name} makes a noise.`);
  }
}

// Child class that inherits from Animal
class Dog extends Animal {
  constructor(name, breed) {
    super(name); // Calls the parent constructor
    this.breed = breed;
  }
  // Override the `speak` method
  speak() {
    console.log(`${this.name} barks.`);
  }
}

const mutt = new Dog("Buddy", "Mutt");

mutt.speak(); // Output: Buddy barks.

โœ… Advantages

  • ๐Ÿ” Code reuse: Prototypes enable you to define methods and properties on a single object that can be shared by many instances, promoting the DRY principle.
  • ๐Ÿ’พ Memory efficiency: Shared methods reduce memory consumption.
  • ๐Ÿ”ง Flexibility: You can modify prototypes at runtime and all inheriting objects will reflect the changes.
  • ๐Ÿงฉ Simplicity: For straightforward object models, prototypal inheritance is lightweight and easy to use.

โš ๏ธ Disadvantages

  • ๐Ÿง  Conceptual complexity: Prototype chains can be confusing for developers from class-based backgrounds.
  • ๐Ÿ“œ Hard to read legacy code: Manual prototype manipulation can be verbose and less readable.
  • ๐Ÿข Performance: Deep prototype chains may slightly impact performance in critical code.
  • ๐Ÿšซ Difficult multiple inheritance: JavaScript lacks native support for multiple inheritance.

๐Ÿ“Œ When to Use

  • ๐Ÿ†• Modern development: Use ES6 class syntax for inheritance.
  • ๐Ÿงผ Simple object extension: Use Object.create() for clean inheritance without constructors.
  • ๐Ÿ”ง Creating utility libraries: Use prototypes to extend built-in types (e.g., Array.prototype) โ€” with caution.

๐Ÿšซ When Not to Use

  • ๐Ÿ’ Silently overriding: Avoid monkey patching built-in prototypes like Object.prototype.
  • ๐Ÿ”„ Instead of composition: Prefer composition over inheritance for complex hierarchies.
  • ๐Ÿงฑ Simple, non-reusable objects: Use object literals for one-off objects.

๐Ÿง  Best Practices and Precautions

  • ๐Ÿ“š Favor ES6 classes: Use class and extends for modern inheritance.
  • ๐Ÿ” Use Object.hasOwn() or hasOwnProperty(): Check for direct properties without traversing the prototype chain.
  • ๐Ÿงต Don't over-rely on deep chains: Deep chains can be hard to debug and maintain.
  • ๐Ÿง  Understand this context: Inside prototype methods, this refers to the calling object, not the prototype.
Back to Index
Previous Classes-ES6-Javascript Encapsulation Next
*
*