The ECMAScript language does not have the concept of abstract classes and interfaces, so it does not have the same inheritance mechanism as other languages. But ECMAScript allows inheritance, based on a chain of stereotypes: the basic idea is to inherit properties and methods of multiple reference types through stereotypes. In the previous article, has analyzed the prototype chain, is not familiar to prototype chain, can be set on an article: https://juejin.cn/post/7028123009613299743

Js implementation of inheritance

1. Borrow constructors
 function Parent(){
     var opt = arguments[0];
     this.name = opt.name;
 }
 function Child(opt){
     Parent.call(this,opt)
     this.age = opt.age;
 }
Copy the code

Use the constructor is in a subclass constructor performs the superclass constructor function body, and amend the context for instance to create a new object, in this way can realize to the parent class constructor parameters, but the disadvantages of this approach is that must be defined in the constructor methods and properties, and a subclass cannot access properties and methods on the prototype, the parent class So this method cannot be used alone.

2. Methods, advantages and disadvantages of inheritance based on prototype chain
    function SuperType() {
        this.name = 'super';
        this.colors = ["red"."blue"."green"];
    }
    function SubType() {}
    / / inherit the SuperType
    SubType.prototype = new SuperType();
    let instance1 = new SubType();
    instance1.colors.push("black");
    console.log(instance1.colors,instance1.name); // "red,blue,green,black" sub
    let instance2 = new SubType();
    console.log(instance2.colors,instance2.name); // "red,blue,green,black" super
Copy the code

The SuperType instance generated by new SuperType() becomes the prototype of SubType. The properties and methods on the SuperType instance become the properties and methods on the prototype of SubType, which are shared by all subclass instances. When the subclass instance operates, the value of the reference type is changed. The value of the original type is not changed. The original value changes because, when we manipulate the property with object[name], if the object doesn’t have one, we add another property to the object, so we don’t modify the property with the same name on the prototype.

The advantages and disadvantages:
  • This approach inherits not only superclass constructors and properties, but also superclass prototype objects.
  • The first disadvantage is that all methods and attributes in the parent constructor are shared by the subclass instance. If the subclass instance changes the value of the reference type, all subclass instances will be affected.
  • The second disadvantage is that a subtype cannot take arguments to the parent type’s constructor when instantiated.

But we generally only inherit from the parent class’s prototype objects. For constructing properties and methods, we ultimately want to generate instance properties and methods, so we should only inherit from the prototype.

      function SuperType() {
        this.name = 'super';
        this.colors = ["red"."blue"."green"];
       }
      SuperType.prototype.flag = true;
    function SubType() {}
    / / inherit the SuperType
    SubType.prototype = SuperType.prototype;
    SubType.prototype.flag = false;
    let instance1 = new SubType();
    console.log(instance1.flag); // false
    let instance2 = new SuperType();
    console.log(instance2.flag); // false

Copy the code

Prototype = supertype. prototype we inherit only the prototype object of the parent class, but there is a problem with this. The subclass and the parent class refer to the same reference, and when the subclass operates on the prototype, it changes the prototype of the parent class as well. Inheritance should not affect upward, so to solve this problem, we need an intermediate object to buffer:

// To optimize this inheritance, we can use intermediate objects to make a buffer to solve the problem
function Super(){
     this.Mskill  = 'Java';
 }
 Super.prototype = {
     name : 'super'.age : 100
 }

 function Buffer(){};
 Buffer.prototype = Super.prototype;
 var buffer = new Buffer();
 Child.prototype = new Buffer();
 function Child(){
     this.skill = 'js';
 }
Copy the code

This separates the prototype of the subclass from the prototype of the parent class, so we can operate on the prototype object of the subclass without affecting the prototype of the parent class, and also inherit the prototype of the parent class. To solve the constructor loss problem caused by rewriting the stereotype, we also need to re-class the constructor property of the subclass to the subclass constructor only, and we can customize a property that points to the superclass constructor.

Enterprise-level encapsulation in this way:

// An optimized way to write inheritance, by encapsulating the method of inheritance, to achieve inheritance between any two classes
 function inherit(Target,Origin){
     var Buffer = function(){};
     Buffer.prototype = new Origin();
     var buffer = new Buffer();
     Target.prototype = buffer;
     Target.prototype.constructor = Target;
     Target.prototype.super_class = Origin;
 }
Copy the code
3. Parasitic combination
 function Parent(){
     var opt = arguments[0];
     this.name = opt.name;
 }
 function Child(opt){
     Parent.call(this,opt)
     this.age = opt.age;
 }
inherit(Child,Parent);
Copy the code

This is the optimal solution, which not only realizes the inheritance of the prototype chain, but also generates the constructor and attribute of the parent class into the subclass instance by borrowing the constructor method, and can also pass parameters to the parent class constructor.

4. Object. The create method

In the above scenario, we create a buffer object to separate the parent stereotype from the subclass stereotype by creating an empty constructor, executing the parent stereotype from the constructor, and then instantiating the empty constructor. But we have a method in place to help us do this, the Object.create method, where parameter 1 receives an Object as a prototype for the generated Object. So we can override the inheritance scheme in this way:

     function inherit(Target,Origin){
     var _prototype = Object.create(Origin.prototype);  // Create an object
     _prototype.constructor = Target;  // Enhance objects
     _prototype.super_class = Origin;
     Target.prototype = _prototype;  // Assignment implements inheritance
 }
Copy the code

So far, js inheritance we have all summed up a time, parasitic combination is the best scheme for reference type inheritance.