“Class” inheritance mechanism of ES6 and Es5

Time:2021-7-29

summary

When interviewing or browsing technical websites, we often encounter such a question: what are the differences between ES6 and Es5 inheritance mechanisms? This article takes you deeper into the principles of ES6 and Es5 inheritance.

Prototype chain

Talking about the inheritance of JS is certainly inseparable from the prototype chain. Let’s review the prototype chain of JS first:

('').__proto__ === String.prototype // true
({}).__proto__ === Object.prototype // true
Object.prototype.__prototype === null // true
function Person () {}
Person.__proto__ === Function.prototype // true
(new Person).__proto__ === Person.prototype // true
(class {}).__proto__ === Function.prototype // true
Function instanceof Function // true
Object instanceof Function // true

From here, we can see that some built-in methods such as strings, objects and functions are due to the prototype chain__proto__Points to the prototype of the corresponding constructorprototype, which inherits the methods on the prototype. In JavaScript, inheritance is also realized through the prototype chain. Let’s first talk about the class of ES6

ES 6 class

class Person {
  constructor (name) {
    this.name = name
  }
  walk () {}
  //Static properties
  static staticFun = function () {
      console.log('staticFun')
  }
}
class Student extends Person {
  constructor (name) {
    super(name)
    this.school = 'NO.3 middle school'
  }
  learn () {}
}

const ming = new Student()
ming.learn()
ming.walk()
Student.staticFun()

In the example, Ming has the learn method because Ming’s__proto__Point to the prototype of the student class

ming.__proto__ === Student.prototype // true

Ming has a walk method because the student prototype can pass__proto__Connect to the prototype of the parent class and find the walk method of the parent class

Student.prototype.__proto__ === Person.prototype
ming.__proto__.__proto__ === Person.prototype

But why does student inherit the staticfun method? Student through their own prototype__proto__You can’t find it because there is no such method on the prototype of the parent class. This is a static method.

In fact, not only student.prototype has__proto__Student has his own__proto__, and his prototype chain points to the constructor of the parent class:

Student.__proto__ === Person // true

This explains that there is no static function staticfun on the student class. Looking up through the prototype chain, it is found that the person class has a static method staticfun.

Inheritance of Es5

JavaScript advanced programming (Third Edition) mentions parasitic combinatorial inheritance:

function SuperType (name) {
  this.name = name
}
SuperType.staticFun = function () { console.log('staticFun') }
SuperType.prototype.sayName = function () { return this.name }
function SubType (name, age) {
  SuperType.call(this, name)
  this.age = age
}
SubType.prototype = Object.create(SuperType.prototype)
SubType.prototype.constructor = SubType
SubType.prototype.sayAge = function () { return this.age }

const demo = new SubType('ming', 22)
demo.sayAge() // ming
demo.sayName() // 22
SubType.staticFun() // throw TypeError

The normal calls of sayage and sayname methods of demo can be expected as follows:

demo.__proto__ === SubType.prototype // true
SubType.prototype.__proto__ === SuperType.prototype // true

So why doesn’t subtype have a staticfun method? Must beSubType.__proto__It doesn’t point to supertype. Where does it point?

SubType.__proto__ === Function.prototype // true
SuperType.__proto__ === Function.prototype // true

Remember the review of the prototype chain at the beginning of the article?

function Person () {}
Person.__proto__ === Function.prototype // true

It can be found here that the traditional parasitic composite inheritance method is different from ES6 class, and cannot automatically inherit the static methods of the parent.

To realize the inheritance of static methods, you only need to modify the prototype chain of subtype and point to supertype:

SubType.__ proto__ =  Super // or object.setprototypeof (subtype, supertype)
SubType.staticFun() // staticFun

summary

The inheritance mechanism of the two is different

In Es5, when the subclass inherits the constructor of the parent class, the subclass’s this already exists, andSuperType.call(this, ...args)To modify the subclass of this

Subclasses of ES6 must be calledsuper(...args)To generate this

The prototype chain of the two constructors points differently

The prototype chain of constructor functions of subclasses and superclasses of Es5 points to function.prototype

The prototype chain of the constructor of the subclass of ES6 points to the constructor of the parent class

appendix

Paste a picture of Babel compiling ES6 class as Es5:

ES6 和 ES5 的"类"继承机制