define

Inheritance means that a child class can use all the functions of its parent class and extend those functions.

Eight ways of inheritance

1. Prototype chain inheritance

introduce

The relationship between constructors, stereotypes, and instances: each constructor has a stereotype object, each stereotype object contains a pointer to the constructor, and each instance contains a pointer to the stereotype object. The essence of inheritance is copying, rewriting the prototype object and replacing it with an instance of a new type.

case

function Parent () {
  this.name = 'Parent'
  this.sex = 'boy'
}
Parent.prototype.getName = function () {
  console.log(this.name)
}
function Child () {
  this.name = 'child'
}
Child.prototype = new Parent()

var child1 = new Child()
child1.getName()
console.log(child1)
/ / print out
// 'child'
// Child{name:"child"}
Copy the code

Referring a prototype object of a child class to an instance of the parent class is called prototype chain inheritance.

Pseudo code:

Child.prototype = new Parent()
Copy the code

Rather than pointing a subclass’s prototype object to a superclass’s prototype object.

Child.prototype = Parent.prototype
Copy the code

conclusion

Advantages:

Inherits the template of the parent class, and inherits the prototype object of the parent class

Disadvantages:

  • If you want to add properties and methods to the prototype of a subclass, you must putChild.prototype = new Parent()After such a statement.
  • Multiple inheritance cannot be implemented because the prototype object has already been formulated.
  • All properties from the stereotype object are shared, so if you accidentally modify the reference type properties in the stereotype object, all instance objects created by subclasses will be affected.
  • When you create a subclass, you cannot pass arguments to the superclass constructor.

2. Structure inheritance

Case study:

function Parent (name) {
  this.name = name
}
function Child () {
  this.sex = 'boy'
  Parent.call(this.'child')}var child1 = new Child()
console.log(child1)
/ / print out
// Child {sex: "boy", name: "bad boy"}
Copy the code

introduce

Use call or apply inside the subclass constructor to call the superclass constructor.

Pseudo code:

function Child () { Parent.call(this, ... arguments) }Copy the code

conclusion

Advantages: It solves the problem that subclass instances share reference objects of the parent class in the prototype chain inheritance, realizes multiple inheritance, and can pass parameters to the parent class when creating subclass instances.

Disadvantages:

  • Constructs can only inherit the instance properties and methods of the parent class, not the properties and methods of the parent stereotype.
  • An instance is not an instance of the parent, just an instance of the subclass.
  • Function reuse is not possible, each subclass has a copy of the parent function, affecting performance.

3. Combination inheritance

introduce

Composite inheritance is an inheritance pattern that combines prototype chain inheritance with constructor inheritance, thus exploiting the best of both.

Ideas:

  • Use stereotype chain inheritance to ensure that subclasses inherit properties and methods from parent stereotypes
  • Use construct inheritance to ensure that a child class inherits instance properties and methods from its parent class

example

function Parent(name){
    console.log(name)
    this.name = name
}
function Child(name){
    Parent.call(this,name)
}
Child.prototype = new Parent()
var child1 = new Child('child')

console.log(child1)
console.log(Child.prototype)

/ / print out

// undefined
// 'child1'

// Child{name:'child1'}
// Parent{name:undefined}
Copy the code

Although new Child() is called only once, the name is printed twice in Parent.

The first time is when the prototype chain is inherited, new Parent().

The second is called by parent-.call () when the inheritance is constructed.

That is, when composite inheritance is used, the superclass constructor is called one more time.

Pseudo code:

// Construct inheritance
function Child () {
  Parent.call(this. arguments) }// Prototype chain inheritance
Child.prototype = new Parent()
/ / correct constructor
Child.prototype.constructor = Child
Copy the code

The constructor

It is a property in the constructor stereotype object that normally points to the stereotype object. This does not affect any JS internal properties, but is used to indicate which constructor generated an instance.

conclusion

advantages

  • You can inherit the properties and methods of a parent instance as well as the properties and methods of a parent stereotype
  • Makes up for the problem of referencing property sharing in prototype chain inheritance
  • Passable parameters, reusable

disadvantages

  • With composite inheritance, the superclass constructor is called twice
  • And two instances are generated. Properties and methods in the instance of the subclass overwrite properties and methods on the prototype of the subclass (the instance of the parent class), thus adding unnecessary memory

4. Parasitic combination inheritance

introduce

example

Object.create(proto,propertiesObject)

Parameter 1: the prototype object to be specified

Parameter 2: An optional parameter that adds new properties and descriptors to the new object itself

function Parent (name) {
  this.name = name
}
Parent.prototype.getName = function () {
  console.log(this.name)
}
function Child (name) {
  this.sex = 'boy'
  Parent.call(this, name)
}
// The difference with composition inheritance
Child.prototype = Object.create(Parent.prototype)

var child1 = new Child('child1')

console.log(child1)
child1.getName()

console.log(child1.__proto__)
console.log(Object.create(null))
console.log(new Object())
Copy the code

As you can see, the only difference between parasitic composition inheritance and composition inheritance is that child-prototype is different.

Pseudo code:

// Construct inheritance
function Child () {
  Parent.call(this. arguments) }// Original type inheritance
Child.prototype = Object.create(Parent.prototype)
/ / correct constructor
Child.prototype.constructor = Child
Copy the code

conclusion

Parasitic combination inheritance is a relatively perfect inheritance way before ES6. Having all the advantages of inheritance above:

  • The superclass constructor is called only once, and only one copy of the superclass property is created
  • Subclasses can use properties and methods from the parent class stereotype chain
  • In normal useintanceOfandisPrototypeOfmethods

5. Original type inheritance

introduce

Create a constructor whose prototype points to the object, then call the new operator to create an instance and return that instance, essentially a shallow copy.

Principle:

function objcet (obj) {
    function F () {};
    F.prototype = obj;
    F.prototype.constructor = F;
    return new F();
}
Copy the code

This can be done directly after ES5 using the object.create () method.

Pseudo code:

var child = Object.create(parent)
Copy the code

conclusion

advantages

  • Without the need to create the constructor, the prototype chain inheritance is implemented, and the amount of code is reduced.

disadvantages

  • Some reference data operations can cause problems, and the two instances will share the reference data type of the inherited instance.
  • Be careful to define methods so that they do not inherit the same method name as the object prototype.
  • You cannot use arguments directly to the parent constructor.

6. Parasitic inheritance

introduce

Enhance the object by wrapping another layer on top of the original type inheritance, and then return the object.

function createAnother (original) {
    var clone = Object.create(original);; // Create a new Object by calling the object.create () function
    clone.fn = function () {}; // Enhance the object in some way
    return clone; // Return this object
}
Copy the code

conclusion

Advantages in the absence of creating a constructor, the implementation of the prototype chain inheritance, the amount of code reduced by part.

disadvantages

  • Some reference data operations are problematic, and both instances inherit the reference data class from the instance.
  • Be careful to define methods so that they do not inherit the same method name as the object prototype.
  • You cannot use arguments directly to the parent constructor.

7. Mixin inheritance

introduce

A subclass that inherits from multiple parent classes can copy properties and methods from multiple objects to the target object. If there are properties with the same name, the following properties will be overwritten.

function Child () {
    Parent.call(this)
    OtherParent.call(this)
}
Child.prototype = Object.create(Parent.prototype)
Object.assign(Child.prototype, OtherParent.prototype)
Child.prototype.constructor = Child
Copy the code

8. Inheritance in class

introduce

Inheritance in a class depends mainly on two things — extends and syuper — and it works the same way as parasitic composition inheritance.

Pseudo code:

class Child extends Parent{
    constructor(. args){
        super(... args) } }Copy the code

extends

Override 4. Example of parasitic composition inheritance:

function Parent (name) {
  this.name = name
}
Parent.prototype.getName = function () {
  console.log(this.name)
}
function Child (name) {
  this.sex = 'boy'
  Parent.call(this, name)
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child

var child1 = new Child('child1')
console.log(child1)
child1.getName()

console.log(child1 instanceof Child)
console.log(child1 instanceof Parent)
/ / print out
// Child{ name: 'child1', sex: 'boy' }
// 'child1'
// true
// true
Copy the code

Rewrite with calss inheritance:

class Parent {
  constructor (name) {
    this.name = name
  }
  getName () {
    console.log(this.name)
  }
}
class Child extends Parent {
  constructor (name) {
    super(name)
    this.sex = 'boy'}}var child1 = new Child('child1')
console.log(child1)
child1.getName()

console.log(child1 instanceof Child)
console.log(child1 instanceof Parent)
/ / print out
// Child{ name: 'child1', sex: 'boy' }
// 'child1'
// true
// true
Copy the code

Let’s compare the results returned:

The class inheritance

Parasitic combination inheritance

As you can see, the class is inherited in a way that is entirely satisfied with parasitic composite inheritance.

The role extends:

  • classCan be achieved byextendsKeyword implementation inherits all properties and methods from the parent class
  • If you useextendsThere is none inside the subclass that implements inheritanceconstructorMethod is added by defaultconstructorandsuper.

super

example

class Parent {
  constructor () {
    this.name = 'parent'}}class Child extends Parent {
  constructor () {
    // Super (name) // Hide super}}var child1 = new Child()
console.log(child1)
child1.getName()
/ / an error
Copy the code

If you do not use super, an error will be reported, so you must call super within Constructor.

This actually has to do with the inheritance mechanism in ES6:

Inheritance in ES5 (such as construct inheritance, parasitic combination inheritance) is essentially creating the instance object this of the child class and then adding the properties and methods of the Parent class to this (using parent-.call (this)).

In ES6, the essence is to create an instance object of the superclass this (using super()), and then use the constructor of the subclass to modify this.

So in class inheritance, a subclass must call super in constructor, otherwise it will create an error. Because a subclass does not have its own this object, it inherits from its parent class, and then processes it. If it does not call super, it will not get this object.

conclusion

  • Inheritance in ES6

Constructor and super are not necessarily required to use the extends implementation inheritance, as they are generated and called by default if they are not.

Extends doesn’t have to be a class, as long as it’s a function that has prototype properties.

  • Super related

There are two ways to call super: as a function call and as an object call.

When super is called, it represents the constructor of the superclass and returns an instance of the subclass. In this case, the “this” inside super refers to the subclass. Super () in the constructor subclass is equivalent to parent-contrustor.call (this).

When super is called as an object, the super object points to the prototype object of the superclass in normal functions and to the superclass in static functions. When a superclass method is called through super, super is bound to this, which is equivalent to parent-prototype.fn.call (this).

Reference article: juejin.cn/post/684490…