Large-scale ethics drama—JavaScript inheritance

Inheritance methods and their applications in JavaScript

In JavaScript, inheritance is an important concept that allows us to create an object and inherit properties and methods from other objects. There are many ways to implement inheritance, each with its own advantages, disadvantages, and applicable scenarios. Below we will explain in detail how each inheritance method works and how to use it.

1. Prototype Chain Inheritance

Prototype chain inheritance implements inheritance by setting the prototype object of the child class to an instance of the parent class. In this way, subclasses can access the properties and methods defined on the prototype of the parent class.

How it works:

Call the parent class constructor using Parent.call(this) and then set the child class’s prototype to an instance of the parent class Child.prototype = new Parent().

Disadvantages: All subclass instances share the reference attributes of the parent class. Modifying the reference attributes of one instance will affect other instances.

Usage examples:

function Parent() { this.name = 'Parent'; }
        Parent.prototype.sayHello = function () { console.log('Hello from ' + this.name); }
        function Child() { this.name = 'Child'; }
        Child.prototype = new Parent();
        var child = new Child(); child.sayHello(); // Output: Hello from Child

2. Constructor Inheritance

Constructor inheritance uses the call or apply method inside the subclass constructor to call the parent class constructor to obtain the properties of the parent class, and each instance has independent properties. .

How it works: Use Parent.call(this, args) inside the child class constructor to call the parent class constructor and pass the parameters.

Disadvantages: Methods on the prototype of the parent class cannot be inherited, only methods defined within the constructor can be inherited.

Usage examples:

function Parent(name) {
            this.name = name;
        }
        Parent.prototype.sayHello = function () {
            console.log('Hello from ' + this.name);
        }
        function Child(name) {
            Parent.call(this, name);
        }
        var child = new Child('Child');
        child.sayHello(); // Output: Hello from Child

3. Combination Inheritance

Combination inheritance combines the advantages of prototype chain inheritance and constructor inheritance. Inherit properties by calling the parent class constructor, use the parent class instance as the prototype object of the child class, and inherit the parent class’s methods.

How it works: Use Parent.call(this, args) inside the subclass constructor to call the parent class constructor, and then set the subclass prototype to Child.prototype = new Parent().

Disadvantages: The parent class constructor will be called twice, causing a waste of performance.

Usage examples:

 function Parent(name) {
            this.name = name;
        }
        Parent.prototype.sayHello = function () {
            console.log('Hello from ' + this.name);
        }
        function Child(name) {
            Parent.call(this, name);
        }
        Child.prototype = new Parent();
        Child.prototype.constructor = Child;
        var child = new Child('Child');
        child.sayHello(); // Output: Hello from Child

4. Prototype Style Inheritance

Prototypal inheritance implements inheritance by creating a temporary constructor and using the parent object as the prototype of the new object. This approach is similar to a shallow copy of an object.

How it works: Define a temporary constructor and use the parent object as the prototype of the new object Object.create(parentObj).

Disadvantages: True encapsulation cannot be achieved, and properties of reference types are shared between the new object and the incoming object.

Usage examples:

 var parent = {
            name: 'Parent',
            sayHello: function () {
                console.log('Hello from ' + this.name);
            }
        }
        var child = Object.create(parent);
        child.name = 'Child';
        child.sayHello(); // Output: Hello from Child

5. Parasitic Inheritance

Parasitic inheritance is based on prototypal inheritance, which creates a new object while enhancing it by adding additional methods or properties.

How it works: Create a new object, add properties and methods to it, and finally return the new object.

Disadvantages: It is also impossible to achieve true encapsulation, and properties of reference types are shared between the new object and the incoming object.

Usage examples:

function createPerson(name) {
  var person = {};
  person.name = name;
  
  person.sayHello = function() {
    console.log("Hello, my name is " + this.name);
  };
  
  return person;
}

var john = createPerson("John");
john.sayHello(); // Output: Hello, my name is John

In this example, we create a new object person through the createPerson function and add the name attribute and sayHello method. Finally, we return this enhanced object.

6. Parasitic Inheritance

Optimize based on combined inheritance to avoid the problem of repeatedly calling the parent class constructor.

How it works: Set the child class prototype to a copy of the parent class prototype Child.prototype = Object.create(Parent.prototype) and then fix the constructor point of the child class prototype.

Usage examples:

function Parent(name) {
  this.name = name;
}

Parent.prototype.sayHello = function() {
  console.log("Hello, my name is " + this.name);
};

function Child(name, age) {
  Parent.call(this, name);
  this.age = age;
}

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

Child.prototype.sayAge = function() {
  console.log("I am " + this.age + " years old.");
};

var john = new Child("John", 25);
john.sayHello(); // Output: Hello, my name is John
john.sayAge(); // Output: I am 25 years old.

In this example, we define two constructors, Parent and Child. By calling Parent.call(this, name), you can call the parent class constructor in the subclass to ensure that the subclass instance has its own properties. Then, we use Object.create to create a copy of the parent class prototype and assign it to the child class prototype so that the child class can inherit the parent class’s methods. Finally, fix the constructor pointer of the subclass prototype so that it points to the subclass itself.

In this way, we can both inherit properties (via constructor calls) and share methods (via prototype chain inheritance). At the same time, the problem of repeatedly calling the parent class constructor is avoided.

Advantages: Inheriting properties and methods avoids repeatedly calling the parent class constructor. It is one of the most commonly used and recommended inheritance methods.