Abstract: function inheritance is a basic and important part of JS, and it is often asked in interviews. The following will take you to quickly understand which of the several inheritance methods in JS that often appear and must be mastered. The interview is almost no problem if you master the following content~

This article is shared from the HUAWEI cloud community " human high-quality JS function inheritance ", author: Northern Lights Night.

I. Introduction:

Function inheritance is a more basic and important part of JS, and it is often asked in interviews. The following will take you to quickly understand which of the several inheritance methods in JS that often appear and must be mastered. The interview is almost no problem if you master the following content~

2. Prototype chain inheritance:

The main point of prototype chain inheritance is that serves as the prototype of the child class . Just look at the following example:

 // 父函数 Person
  function Person(name, age) {
    // 定义一些属性
    this.name = name;
    this.age = age;
    this.nature = ["auroras", "wind", "moon"];
  }
 // 定义Person原型上的一个方法
  Person.prototype.sayLove = function () {
    console.log(this.name + " like " + this.nature[0]);
  };
 
  // 子函数 Jack
  function Jack() {}
  // 父类的实例作为子类的原型 (-------------------实现核心--------------------------)
  Jack.prototype = new Person();

Now we create two instances of Jack and test to see if the inheritance of Person is implemented:

  var jack1 = new Jack();
  var jack2 = new Jack();
  jack2.nature[0] = "sea";
  jack1.sayLove();
  jack2.sayLove();   
  console.log(jack1.nature);
  console.log(jack2.nature);  

Seeing that the running result is indeed inherited, the sayLove method can be executed. But there are many shortcomings. When creating a Jack instance, the parameters name and age cannot be passed, and the nature reference type attributes . Any change will change:
image.png

3. Borrowing constructor inheritance (object disguise):

The core is "constructor stealing". Call the parent class constructor in the subclass constructor. Because after all functions are simple objects that execute code in a specific context, you can use the apply() and call() methods to execute the constructor with the newly created object as the context. It can resolve the conflicts between the parameters passed in the prototype chain inheritance and the attributes of the reference type. Or look at the example directly:

// 父函数 Person
 function Person(name, age) {
   // 定义一些属性
   this.name = name;
   this.age = age;
   this.nature = ["auroras", "wind", "moon"];
 }
// 定义Person原型上的一个方法
 Person.prototype.sayLove = function () {
   console.log(this.name + " like " + this.nature[0]);
 };

 // 子函数 Lucy
 function Lucy(name, age) {
 // 通过call把this指向Lucy,相当于拷贝了一份父函数 Person 里的内容(---------实现核心--------------)
       Person.call(this, name, age);
     }
 //给子函数原型上也定义一个方法
  Lucy.prototype.syaName = function () {
       console.log("My name is " + this.name);
     };

Now we create two instances of Lucy and test to see if the inheritance of Person is implemented:

  var lucy1 = new Lucy("lucy1", "20");
  var lucy2 = new Lucy("lucy2", "22");
  lucy2.nature[0] = "sea";
  console.log(lucy1.name);
  console.log(lucy1.nature);
  console.log(lucy2.nature);
  lucy1.syaName();
  lucy2.syaName();
  lucy1.sayLove();

As a result, it can be inherited, parameters can be passed, and attributes of reference types do not affect each other, but the shortcomings are obvious, you can see the error, you can not use the method sayLove on the prototype of the parent class.
image.png

Four. Combination inheritance:

Combinatorial inheritance is an inheritance method that combines the core implementation of prototype chain inheritance and borrowed constructor inheritance. It can pass parameters and reference type attributes without affecting each other, and at the same time, subclasses can also obtain methods of parent classes. This is also the more commonly used inheritance method at present. Look directly at the example:

 // 父函数 Person
  function Person(name, age) {
    // 定义一些属性
    this.name = name;
    this.age = age;
    this.nature = ["auroras", "wind", "moon"];
  }
 // 定义Person原型上的一个方法
  Person.prototype.sayLove = function () {
    console.log(this.name + " like " + this.nature[0]);
  };
 
  // 子函数Lisa
      function Lisa(name, age) {
// 通过call把this指向Lisa,相当于拷贝了一份父函数 Person 里的内容(------实现核心-----------)      
        Person.call(this, name, age);
      }
// 父类的实例作为子类的原型 (--------------实现核心-------------------)      
      Lisa.prototype = new Person();
  //小知识点,这里是让Lisa的constructor重新指向Lisa,不然因为Lisa的原型为Person实例,constructor会指向Person
      Lisa.prototype.constructor = Lisa;

Now we create two instances of Lisa and test to see if the inheritance of Person is implemented:

  var lisa1 = new Lisa("lisa1", "20");
  var lisa2 = new Lisa("lisa2", "21");
  lisa2.nature[0] = "sea";
  console.log(lisa1.name);
  console.log(lisa1.nature);
  console.log(lisa2.nature);
  lisa1.sayLove();
  lisa2.sayLove();

You can see that the functions we inherited are basically realized. Also repaired the shortcomings of prototype chain and borrowed constructor inheritance. However, it still has a small shortcoming, that is, you can see that in the code comment implementation core, Person is called twice, then there two copies of the same attribute on the Lisa prototype and the instance, 1614041724ddb1, then there will be more or less Some performance wasted.
image.png

5. Parasitic combination inheritance:

In fact, parasitic combinatorial inheritance is similar to combinatorial inheritance, that is, there is an additional solution to the shortcomings of the prototype and the instance producing two copies of the same property on combinatorial inheritance. The core solution is that since we just want the prototype of the subclass to be assigned to the prototype of the parent, there is no need to create a new instance of the parent. Create a new object directly, its value is the prototype of the parent class, and then assign it to the prototype of the subclass.

The Object.create(proto,[propertiesObject]) method is used to create a new object. The __proto__ of the new object is its parameter proto. Of course, Object.create may not have a lower version of ie, so the Object.create method is also custom-encapsulated below, of course, it is just a simple encapsulation. Look directly at the example:

 // 父函数 Person
  function Person(name, age) {
    // 定义一些属性
    this.name = name;
    this.age = age;
    this.nature = ["auroras", "wind", "moon"];
  }
 // 定义Person原型上的一个方法
  Person.prototype.sayLove = function () {
    console.log(this.name + " like " + this.nature[0]);
  };
 
  // 子函数 Andy
 function Andy(name, age) {
        Person.call(this, name, age);
      }
// 如果没有 Object.create()方法,简单封装下
      if (!Object.create) {
        Object.create = function (proto) {
          function Temp() {}
          Temp.prototype = proto;
          return new Temp();
        };
      }
// 调用Object.create方法,新建一对像,其__proto__为Person.prototype,并赋值给 Andy.prototype (-------实现核心----------)
      Andy.prototype = Object.create(Person.prototype);
  //修改constructor指向
      Andy.prototype.constructor = Andy;

Now we create two instances of Andy, test to see if the inheritance of Person is implemented:

  console.log(Andy.prototype.__proto__ === Person.prototype);
  var andy1 = new Andy("andy1", "20");
  var andy2 = new Andy("andy2", "21");
  andy2.nature[0] = "sea";
  console.log(andy1.name);
  console.log(andy1.nature);
  console.log(andy2.nature);
  andy1.sayLove();
  andy2.sayLove();

Perfect operation:
image.png

Six.class inheritance:

After ES6 has the class syntactic sugar, you can define classes through class and implement class inheritance. Look directly at the example:

//定义一个父类 Animal
  class Animal {
   //这里constructor指向类本身,跟es5行为一样的
    constructor(name) {
      this.name = name;
    }
    likeEat() {
      console.log(this.name + " like eat " + this.food);
    }
  }
//定义一个子类 Dog ,通过 extends 继承父类Animal
  class Dog extends Animal {   
    constructor(name, food) {
      //通过super(属性名)继承父类属性
     super(name);
     this.food = food;
    }
    likeEat() {
     //通过super.+父类方法 实现继承父类方法
      super.likeEat();
    }
  }

New a Dog instance, test to see if Dog inherits Animal:

var jinmao = new Dog("jinmao", "bone");
console.log(jinmao.name);
jinmao.likeEat();

You can see the perfect realization:
image.png

Seven. Summary:

image.png

The above is the entire content of this article, if there is an error, please point it out~

Click to follow and learn about Huawei Cloud's fresh technology for the first time~


华为云开发者联盟
1.4k 声望1.8k 粉丝

生于云,长于云,让开发者成为决定性力量