Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Object Creation and Inheritance Patterns in JavaScript

Tech Apr 24 11

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...

SBUS Signal Analysis and Communication Implementation Using STM32 with Fus Remote Controller

Overview In a recent project, I utilized the SBUS protocol with the Fus remote controller to control a vehicle's basic operations, including movement, lights, and mode switching. This article is aimed...

Comprehensive Guide to Hive SQL Syntax and Operations

This article provides a detailed walkthrough of Hive SQL, categorizing its features and syntax for practical use. Hive SQL is segmented into the following categories: DDL Statements: Operations on...

Leave a Comment

Anonymous

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