Fading Coder

One Final Commit for the Last Sprint

Home > Tools > Content

Implementing Inheritance in JavaScript Using Prototype Chains

Tools 1

In object-oriented programming, inheritance allows new types to acquire properties and methods from existing ones. JavaScript supports implementation inheritance primari through prototype chains, as it lacks interface inheritance due to functions not having signatures.

Prototype Chain Mechanism

A prototype chain enables inheritance by linking objects through their prototypes. Each constructor has a prototype object, which points back to the constructor, and instances have an internal link to this prototype. When a prototype is set to an instance of another type, it creates a chain where properties and methods can be inherited upward.

function ParentClass() {
    this.parentFlag = true;
}
ParentClass.prototype.fetchParentFlag = function() {
    return this.parentFlag;
};

function ChildClass() {
    this.childFlag = false;
}
// Inherit from ParentClass
ChildClass.prototype = new ParentClass();
ChildClass.prototype.fetchChildFlag = function() {
    return this.childFlag;
};

let obj = new ChildClass();
console.log(obj.fetchParentFlag()); // true

In this example, ChildClass inherits from ParentClass by assigning a new ParentClass instance to ChildClass.prototype. This overrides the original prototype, allowing ChildClass instances to access methods from ParentClass.prototype. The fetchParentFlag method resides on ParentClass.prototype, while parentFlag is an instance property on ChildClass.prototype.

Property lookup follows the chain: when accessing a property on an instance, JavaScript searches the instance, then its prototype, and continues up the chain. For obj.fetchParentFlag(), it checks obj, ChildClass.prototype, and ParentClass.prototype.

Determining Inheritance Relationships

Use instanceof to check if an instance's prototype chain contains a constructor:

console.log(obj instanceof ParentClass); // true
console.log(obj instanceof ChildClass); // true

Alternatively, isPrototypeOf() verifies if a prototype is in the chain:

console.log(ParentClass.prototype.isPrototypeOf(obj)); // true
console.log(ChildClass.prototype.isPrototypeOf(obj)); // true

Modifying Methods in Inheritance

To override or add methods, define them after setting up the prototype chain to avoid breaking it.

function ParentClass() {
    this.parentFlag = true;
}
ParentClass.prototype.fetchParentFlag = function() {
    return this.parentFlag;
};

function ChildClass() {
    this.childFlag = false;
}
ChildClass.prototype = new ParentClass();

// Add new method
ChildClass.prototype.fetchChildFlag = function() {
    return this.childFlag;
};
// Override inherited method
ChildClass.prototype.fetchParentFlag = function() {
    return false;
};

let obj = new ChildClass();
console.log(obj.fetchParentFlag()); // false

Using object literals to redefine the prototype can disrupt the chain, as it replaces the prototype entirely.

function ParentClass() {
    this.parentFlag = true;
}
ParentClass.prototype.fetchParentFlag = function() {
    return this.parentFlag;
};

function ChildClass() {
    this.childFlag = false;
}
ChildClass.prototype = new ParentClass();

// This breaks the inheritance
ChildClass.prototype = {
    fetchChildFlag() {
        return this.childFlag;
    },
    anotherMethod() {
        return false;
    }
};

let obj = new ChildClass();
console.log(obj.fetchParentFlag()); // Error: method not found

Limitations of Prototype Chains

A key issue arises with reference values in prototypes, as they are shared across all instances.

function ParentClass() {
    this.items = ["apple", "banana", "cherry"];
}
function ChildClass() {}
ChildClass.prototype = new ParentClass();

let obj1 = new ChildClass();
obj1.items.push("date");
console.log(obj1.items); // ["apple", "banana", "cherry", "date"]
let obj2 = new ChildClass();
console.log(obj2.items); // ["apple", "banana", "cherry", "date"]

Here, items is a reference value on ParentClass.prototype, so modifications affect all ChildClass instances. Additionally, prototype chains do not allow passing arguments to parent constructors during child instantiasion, limiting flexibility. Due to these drawbacks, prototype chains are often combined with other patterns for practical use.

Related Articles

Efficient Usage of HTTP Client in IntelliJ IDEA

IntelliJ IDEA incorporates a versatile HTTP client tool, enabling developres to interact with RESTful services and APIs effectively with in the editor. This functionality streamlines workflows, replac...

Installing CocoaPods on macOS Catalina (10.15) Using a User-Managed Ruby

System Ruby on macOS 10.15 frequently fails to build native gems required by CocoaPods (for example, ffi), leading to errors like: ERROR: Failed to build gem native extension checking for ffi.h... no...

Resolve PhpStorm "Interpreter is not specified or invalid" on WAMP (Windows)

Symptom PhpStorm displays: "Interpreter is not specified or invalid. Press ‘Fix’ to edit your project configuration." This occurs when the IDE cannot locate a valid PHP CLI executable or when the debu...

Leave a Comment

Anonymous

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