As you can see, mastering js object inheritance is so easy

·

4 min read

Prototype chain inheritance

Inheritance is achieved by pointing the prototype of a child class to an instance of the parent class. If a parent class has a private property of reference type, then this property is shared by all subclasses when it is inherited as a public property, and any change to the current property by any subclass will affect all other inherited subclasses.

Advantages

  • Subclasses can access the prototype methods and properties added by the parent class.
  • Simple and easy to use.

Disadvantages

  • Subclasses can only inherit from a single parent class, no multiple inheritance is possible.
  • The properties of the prototype object are shared by all instances.
  • Subclass instances cannot dynamically pass parameters to the parent's constructor.
  • New methods of subclasses must be placed after prototype replacement.

Instances

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.children = [1, 2];
    this.setName = function() {};
}

Person.prototype.addChild = function() {};

function Student(score) {
    this.score = score;
    this.setScore = function() {};
}


// The prototype of the child class is used as an instance object of the parent class to achieve the inheritance relationship
Student.prototype = new Person();
// The prototype will be overridden and the newly defined methods need to be placed after the prototype replacement.
Student.prototype.sayName = function() {};

var student1 = new Student(1000);
var student2 = new Student(2500);

student1.children.push(3);

console.log(student1);
console.log(student2);
console.log(student1.children); // [1, 2, 3]
console.log(student2.children); // [1, 2, 3]
console.log(student1.__proto__ === student2.__proto__); // true point to Student
console.log(student1.__proto__. __proto__ === student2.__proto__. __proto__); // true points to Person

Constructor inheritance

The parent constructor is called from within the subtype constructor via call().

Advantages

  • Solves the problem of subclass instances sharing parent reference properties in prototype chain inheritance.
  • Enables a single subclass to inherit from multiple parent classes.
  • Subclass instances can dynamically pass parameters to the parent class.

Disadvantages

  • Poor function reusability, each subclass creates a copy of the parent instance function, which affects performance.
  • Instances are only instances of the child class and not of the parent class.
  • Subclasses can only inherit the instance properties and methods of the parent class, and cannot inherit properties and methods on the prototype.

Example

function Person(name, age) {
    this.name = name;
    this.age = age;
    this.children = [1, 2];
    this.setName = function() {};
}

Person.prototype.addChild = function() {};

function Student(name, age, score) {
    Person.call(this, name, age);
    this.score = score;
    this.setScore = function() {};
}

var student1 = new Student('Jhon', 26, 1000);
console.log(student1);
console.log(student1.addChild); // undefined
console.log(student1.__proto__); // Student
console.log(student1.__proto__. __proto__); // Object

Combinatorial Inheritance (Prototype Chain + Constructor Combinatorial Inheritance)

Combined inheritance is the inheritance of prototype properties and methods using a prototype chain and instance properties using a constructor.

Disadvantages

  • Subtypes cannot dynamically pass parameters to supertypes.
  • The supertype constructor will be called twice.

Example

function Parent(username, password) {
    this.password = password
    this.username = username
}

Parent.prototype = {
    login() {
        console.log(`login as , ${this.username}, password is ${this.password}. `)
    }
}

function Child(username, password) {
    Parent.call(this, username, password) // second call
    this.articles = 30
}
Child.prototype = new Parent() // first call
// Child.prototype = Object.create(Parent.prototype) // This approach avoids the problems with the current inheritance approach

const user = new Child('jweboy', 'jl0630')
// user.login()
// console.log(user.articles)

Prototype inheritance

Prototype inheritance means creating a temporary constructor, then using the incoming object as a prototype for that constructor, and finally returning a new instance of the temporary type. ECMAScript5 adds the Object.create method to standardize proto-typing inheritance.

// The following method is also a concrete implementation of Object.create
function object(obj) {
    function F() {}
    F.prototype = obj;
    return new F();
}

Parasitic inheritance

Parasitic inheritance is the creation of a function that is used only to encapsulate the inheritance process, which internally augments the object in some way and finally returns that object.

Disadvantages

  • Similar to constructors, functions are hard to reuse.
function createObject(obj) {
    const clone = Object.create(obj); // create a new object
    clone.run = function() { // some way to enhance the object
        return this.name;
    };
    return clone; // return the object
}
const obj = createObject({ name: 'tao' });
// obj.run(); // 'tao'
// console.dir(obj);

Parasitic Combinatorial Inheritance

Parasitic combinatorial inheritance is inheriting properties through constructors and methods through prototype chains.

Advantages

  • Subtypes can pass parameters to supertypes dynamically.
  • Constructors of supertypes are executed only once.
  • Subtype properties are created in their own prototype chains, and properties are not shared between subtypes.
function inheritPrototype(child, parent) {
    // Create a copy of the supertype prototype
    const prototype = Object.create(parent.prototype)
    // Override the missing constructor property for the created copy
    prototype.constructor = child
    // the created copy is assigned to the prototype of the subtype
    child.prototype = prototype
child.prototype = prototype }

function Parent(username, password) {
    this.password = password
    this.username = username
}

Parent.prototype.login = function() {
    console.log(`login as , ${this.username}, password is ${this.password}. `)
}

function Child(username, password) {
    Parent.call(this, username, password) // property inheritance
    this.articles = 30
}

// Inheritance
inheritPrototype(Child, Parent)

Child.prototype.read = function() {
    console.log('read article at', this.articles)
}

const user = new Child('jweboy', 'jl0630')
// console.dir(user)

Reference Resources

Did you find this article valuable?

Support Jweboy's blog by becoming a sponsor. Any amount is appreciated!