Mastering JavaScript Objects and Prototypal Inheritance

Introduction to JavaScript Objects

In JavaScript, an object is a self-contained environment that stores data as a collection of properties and methods. A property is an association between a name (or key) and a value, while a method is a function associated with an object.

Think of an object as a real-world entity. For example, a Car is an object. It has properties like color, brand, and weight, and methods like start, drive, and brake.

// A simple conceptual look at an object
let car = {
    brand: "Tesla",      // Property (key: value)
    color: "Red",        // Property
    start: function() {  // Method
        console.log("Engine started!");
    }
};

Types of Objects in JavaScript

While almost everything in JavaScript is an object (or acts like one), they generally fall into three main categories:

1. Native / Built-in Objects

These are standard objects provided by JavaScript out of the box as part of the language specification:

  • Data Structures: Object, Array, Map, Set
  • Utility Objects: Math, Date, RegExp (Regular Expressions), JSON

2. Host Objects

These are supplied by the environment running JavaScript (like a web browser or Node.js):

  • Browser Environment (Web APIs): window, document (DOM), history, fetch
  • Node.js Environment: process, fs (File System), path

3. User-Defined Objects

These are custom objects created by you, the developer, to suit your specific application needs.

Creating Objects in JavaScript

There are several ways to create objects in JavaScript:

1. Object Literal

The simplest and most readable way to create an object is using curly braces {}.

const user = {
    firstName: "Jane",
    lastName: "Doe",
    age: 28
};

2. Using the new Object() Syntax

You can use the built-in Object constructor, though this is generally less preferred than the literal syntax.

const user = new Object();
user.firstName = "Jane";
user.lastName = "Doe";
user.age = 28;

3. Constructor Functions

Useful when you need a blueprint to create multiple objects of the same type. Conventionally, constructor functions start with a capital letter.

function Person(first, last, age) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
}

// Creating instances
const user1 = new Person("Jane", "Doe", 28);
const user2 = new Person("John", "Smith", 34);

4. Object.create()

This method creates a new object, using an existing object as the prototype of the newly created object.

const protoUser = {
    greeting: function() {
        return `Hello, my name is ${this.name}`;
    }
};

const user = Object.create(protoUser);
user.name = "Jane"; // Inherits the greeting method

Object Methods

A method is simply a property containing a function definition. Methods allow objects to “do” things.

Defining Methods

You can define methods inside an object literal in two ways:

const calculator = {
    // Traditional way
    add: function(a, b) {
        return a + b;
    },
    // Modern ES6 shorthand (Recommended)
    subtract(a, b) {
        return a - b;
    }
};

console.log(calculator.add(5, 3));      // Output: 8
console.log(calculator.subtract(5, 3)); // Output: 2

Constructor Functions and the ‘new’ Keyword

A Constructor Function is a regular function used as a blueprint to create multiple objects of the same type. To create an instance, we use the new keyword.

function Player(name, level) {
    this.name = name;
    this.level = level;
}

const player1 = new Player("Nova", 5);
console.log(player1.name); // Output: Nova

What happens when the ‘new’ keyword is used?

  1. A new empty object {} is created.
  2. The this keyword is bound to this new object.
  3. The code inside the constructor function executes, assigning properties to this.
  4. The newly created object is automatically returned.

Prototypes in JavaScript

Every function and object has a built-in property called a Prototype. Prototypes are the mechanism by which JavaScript objects inherit features from one another.

  • Function.prototype: The blueprint assigned as the prototype to any objects created by this function using the new keyword.
  • [[Prototype]] (or __proto__): An internal hidden link pointing to an object’s constructor’s prototype.

Attaching methods to the prototype instead of the constructor saves memory:

function Player(name, level) {
    this.name = name;
    this.level = level;
}

Player.prototype.levelUp = function() {
    this.level++;
    console.log(`${this.name} advanced to level ${this.level}!`);
};

const player1 = new Player("Nova", 5);
player1.levelUp(); // Output: Nova advanced to level 6!

Inheritance Using the Prototype Chain

When you access a property or method, JavaScript looks for it on the object, then its prototype, and so on. This sequence is the Prototype Chain.

Implementing Prototypal Inheritance

// 1. Parent Constructor
function Character(name) {
    this.name = name;
}
Character.prototype.greet = function() {
    return `Hello, I am ${this.name}`;
};

// 2. Child Constructor
function Mage(name, spell) {
    Character.call(this, name);
    this.spell = spell;
}

// 3. Link prototypes
Mage.prototype = Object.create(Character.prototype);

// 4. Reset the constructor pointer
Mage.prototype.constructor = Mage;

// 5. Add unique methods
Mage.prototype.castSpell = function() {
    return `${this.name} casts ${this.spell}!`;
};

const gandalf = new Mage("Gandalf", "Fireball");
console.log(gandalf.greet());     // Output: Hello, I am Gandalf
console.log(gandalf.castSpell());  // Output: Gandalf casts Fireball!