Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Object Creation and Inheritance Patterns in JavaScript

Tech 2

Defining Classes in ES5

In the ES5 standard, classes are implemented using constructor functions. There are several patterns for assigning properties and methods.

Instance-Level Definitions

Methods and properties can be defined directly inside the constructor function. While this allows for easy parameterization, it causes memory overhead because every new instance receives its own copy of the methods.

function Gadget(model, price) {
  this.model = model;
  this.price = price;
  this.type = 'Hardware';
  this.startup = function () {
    console.log(this.model + ' is booting up...');
  };
}

Prototype-Level Definitions

To optimize memory, shared methods and static-like properties are typically attached to the prototype. This ensures that all instances point to the same memory location for these functions.

function Gadget(model) {
  this.model = model;
}

Gadget.prototype.type = 'Hardware';
Gadget.prototype.displayInfo = function () {
  console.log('Model: ' + this.model);
};

// Alternative literal syntax for prototype assignment
Gadget.prototype = {
  constructor: Gadget,
  type: 'Hardware',
  displayInfo: function () {
    console.log('Model: ' + this.model);
  }
};

In practice, developers combine these approaches: instance-specific data (unique attributes) is placed in the constructor, while shared behavior (methods) is placed on the prototype.

Modern ES6 Class Syntax

ES6 introduced a more declarative syntax that mirrors traditional class-based languages, though it remains based on prototypes under the hood.

class Vehicle {
  constructor(make, year) {
    this.make = make;
    this.year = year;
    this.engineStatus = 'off';
  }

  identify() {
    console.log(`This is a ${this.year} ${this.make}.`);
  }
}

class Sedan extends Vehicle {
  constructor(make, year, doors) {
    // super() invokes the parent constructor
    super(make, year);
    this.doors = doors;
  }

  honk() {
    console.log('Beep beep!');
  }
}

const myCar = new Sedan('Toyota', 2022, 4);
myCar.identify(); // Output: This is a 2022 Toyota.
myCar.honk();     // Output: Beep beep!

Inheritance Patterns in ES5

Prototype Chain Inheritance

This pattern involves setting the child's prototype to a new instance of the parent.

function Parent() {
  this.traits = ['patient', 'kind'];
}
Parent.prototype.sayHello = function() {
  console.log('Hello');
};

function Child() {}
Child.prototype = new Parent();

const kid = new Child();
kid.sayHello(); // Inherited from Parent prototype
  • Pros: Simple to implement; inherits from both the instance and the prototype.
  • Cons: Cannot pass arguments to the parent during child instantiation; all child instances share the same reference-type properties (like arrays).

Constructor Stealing (Functional Inheritance)

By using .call() or .apply(), the child executes the parent's constructor in its own context.

function Base(id) {
  this.id = id;
}

function Extended(id, label) {
  Base.call(this, id); // Inherit instance properties
  this.label = label;
}

const obj = new Extended(101, 'Main');
console.log(obj.id); // 101
  • Pros: Supports multiple inheritance and argument passing.
  • Cons: Only inherits instance properties; methods defined on the parent's prototype are inaccessible.

Parasitic Combination Inheritance

This is widely considered the most efficient inheritance pattern in ES5. It avoids calling the parent constructor twice while maintaining a clean prototype chain.

function Animal(species) {
  this.species = species;
}
Animal.prototype.move = function() {
  console.log(this.species + ' is moving.');
};

function Bird(species, flySpeed) {
  Animal.call(this, species); // Step 1: Inherit properties
  this.flySpeed = flySpeed;
}

// Step 2: Inherit methods via a clean prototype link
(function() {
  var Surrogate = function() {};
  Surrogate.prototype = Animal.prototype;
  Bird.prototype = new Surrogate();
  Bird.prototype.constructor = Bird;
})();

const eagle = new Bird('Eagle', '50mph');
eagle.move(); // Eagle is moving.

This method isolates the prototype linking from the execution of the parent constructor logic, ensuring instances are initialized correctly without redundant property overhead.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.