current position:Home>Have you learned the 7 methods of JS inheritance?

Have you learned the 7 methods of JS inheritance?

2021-08-27 08:41:43 Xiao Cheng

This is my participation 8 The fourth of the yuegengwen challenge 23 God , Check out the activity details :8 Yuegengwen challenge

Hello everyone , I'm Xiao Cheng's classmate , This article mainly writes JavaScript Medium 7 There are two ways of inheritance , Deeply understand the problems of each method and how the new method solves the problems

Thank you very much for reading , You are welcome to correct the wrong places

May your life be bright , Everything is lovely

Preface

In the last article, we explained the mechanism of prototype chain and some properties related to prototype , What is closely related to the prototype chain is inheritance , Why do you say that ?

stay 《JavaScript Advanced programming 》 On , There's a phrase

“ Implementing inheritance is ECMAScript The only way to support inheritance , And this is mainly through Prototype chain To achieve .”

As one can imagine , Prototype chain plays an important role in inheritance

Before the full text begins , Let's take a look at the outline of this article

image-20210816230355022

Closely related 6 There are two ways of inheritance

stay ES6 Before coming , be based on ES5 Inheritance of realization , In each generation, the problems brought by the previous generation are optimized , This is also JavaScript What is worth learning in language , Have a problem , solve the problem , Continuous optimization , Next, let's see how they are implemented step by step

One 、 Prototype chain inheritance

1. The basic idea

The basic idea of prototype chain inheritance is through Prototype To inherit properties and methods of multiple reference types

Realized The basic idea Is to instantiate an object using a constructor , adopt new keyword , take The instance object of the constructor Prototype object as subclass function

2. Implementation method

//  Define the parent function 
function Father() {
    //  Define parent class properties 
    this.name = 'father'
}
//  Add methods to the prototype of the parent class 
Father.prototype.say = function () {
    console.log(' I'm daddy ');
}
//  Create subclass functions 
function Son() {}
//  Implementation inheritance 
Son.prototype = new Father()
//  Print reference 
console.log(Son.prototype) // Father {name: "father"}
 Copy code 

Let's explain the code above , First, a parent function and a child function are defined , Added some properties and methods

The key to inheritance is Son.prototype = new Father() . How does it understand

First of all, we need to understand new Operator execution

  1. Create an empty object
  2. Inherit function prototype , Put this new object's __proto__ Property is assigned to the prototype object of the constructor
  3. Inside the constructor this Point to a new object
  4. Execute function body
  5. Return to this new object

got it new After , We can know when we are new Father() In operation , This step will be Father The prototype object of the constructor is packaged to Father Instance object of , That is to say father.__proto__ = Father.prototype , Change here, that is Son.prototype.__proto__ = Father.prototype, In this way, it is The instance object of the parent class is used as the prototype of the child class , This also enables the connection between the child class and the parent class

Critical code :son.prototype = new Father()

3. The problem is

Through the above analysis , On the whole, I don't feel anything wrong , But let's take a look at this example

function Father() {
	//  Define the parent class attribute as the reference data type 
	this.a = [1, 2, 3, 4]
}
 Copy code 

We put the above code in a Change the value of to the reference data type , We know that for a reference data type, only the reference to it will be saved , That's the memory address .

Let's first create two subclasses that inherit this parent class son1 ,son2

let son1 = new Son()
let son2 = new Son()
 Copy code 

Then we want to son1 Medium a Add a value to the array 5 , We'll do this

son1.a.push(5)
 Copy code 

Don't think too much. son1 You must have successfully added , But let's print it again son2, We'll find it a The array has also been changed

image-20210817083710044

This is the problem that the reference data type is shared by subclasses caused by the prototype chain inheritance

4. Advantages and disadvantages

advantage :
  • Methods of the parent class can be reused
  • It's easy to operate
shortcoming
  • For reference data types, data is shared by subclasses , That is, change one, and everything else will change
  • When creating a subclass instance , Cannot pass parameter to parent constructor , inflexible .

Two 、 Stealing constructor inheritance

In order to solve the problem that reference values cannot be shared due to the inheritance of prototype chain , Thus, a kind of “ Stealing constructor inheritance ” The way

1. The basic idea

In order to achieve Reference value sharing The problem of , We can't directly use the reference value on the prototype object for subclasses .

therefore , You can call the parent class constructor in the child class constructor .

Let's start with a simple piece of code

function Son() {
	this.a = [1, 2, 3, 4]
}
 Copy code 

If we rewrite the subclass code like this , What will happen ?

When we go through Son Constructor instantiates an instance object , Variables in each instance object a They're all independent , Own , When we modify one , Does not affect the value of another

image-20210817092755942

This is the principle of stealing constructor inheritance

2. Implementation method

function Father() {
    this.a = [1, 2, 3, 4]
}

function Son() {
    Father.call(this)
}
let son1 = new Son()
let son2 = new Son()
son1.a.push(5)
console.log(son1, son2)
 Copy code 

We can see , In the above implementation , Not directly this.a... Instead, it adopted Father.call(this)

If you use this.a Words , Is this also called inheritance ? Is that so?

So using Father.call(this) What's the reason ?

We originally directly put this.a Directly written in the subclass function , This is called directly in the subclass Father The method is similar , The only difference is this Point to the problem

If it is called directly in the subclass Father() , So it's this Will point to window , In this way, the data cannot be bound to the instance , So we need to change this The direction of , Point to the current subclass constructor

In this way, the data can be bound to each instance object

At the same time, because our key statement is call, Therefore, we can pass parameters to the parent class constructor , Pass parameters

3. The problem is

From the implementation code above , I believe you can see , I deliberately ignored the operation of the prototype , No method was added to the prototype of the parent constructor , And this is the problem of this method

Father.prototype.say = function () {
    console.log(111);
}
 Copy code 

image-20210817095321861

Cannot find on subclass say Method

4. Advantages and disadvantages

advantage :
  • Solved the problem that reference values cannot be shared
  • Can pass parameters
shortcoming :
  • Only instance properties and methods of the parent class can be inherited , Cannot inherit from the parent class Prototype Properties and methods
  • The parent method cannot be reused . Every time a subclass is instantiated , To execute the parent function . Redeclare the method defined by the parent class , Cannot reuse .

3、 ... and 、 Combination inheritance

In the first two methods , There are certain defects , So they are rarely used alone . Therefore, a new way of inheritance was born : Combination inheritance ( Pseudo classical inheritance ), Composite inheritance combines the prototype chain with the method of stealing constructor inheritance , Combine the advantages of both .

1. The basic idea

Inherit the properties and methods on the parent class prototype through prototype chain inheritance , Then inherit the properties on the instance by stealing the constructor

such , The method is defined on the prototype to realize reuse , It also ensures that each instance has its own properties

2. Implementation method

Combine the two methods with

function Father() {
    this.a = [1, 2, 3, 4]
}
Father.prototype.say = function () {
    console.log(111);
}
function Son() {
    Father.call(this)
}
Son.prototype = new Father()
let son1 = new Son()
let son2 = new Son()
 Copy code 

In fact, it just adds the key code inherited by the prototype chain on the basis of stealing the constructor

Son.prototype = new Father()
 Copy code 

In the code above , Inherits the properties on the parent class instance by stealing the constructor method a , By way of prototype chain , The prototype object that inherits the parent class

The specific process is only a combination of two , You can turn to the previous explanation

3. The problem is

First, let's print son1 and son2

image-20210817114337643

This result is output , We found that there is also an attribute on its prototype object a , But this seems to be the initial value , Let's think about why ?

We will Father The instance of is bound to Son On the prototype of , But we steal the constructor method

take Father Its own properties were manually added to Son The body of , So in Son On the instantiated object , There will be one. a attribute , There will also be one on the prototype a attribute

What problems will this cause ?

Before I answer that question , Let's first count the number of calls Father Constructors ,

  1. stay new When
  2. stay call When

Therefore, on the one hand, there will be some performance problems , Another aspect is that there will be 2 Attributes

4. Advantages and disadvantages

advantage :
  • Solve the problem that attributes are shared in prototype chain inheritance
  • Solve the problem of borrowing constructor to solve the problem that cannot inherit the parent class prototype object
shortcoming :
  • Called the parent function twice , Performance issues
  • Due to two calls , It will cause the instance and prototype to have the same properties or methods

Four 、 Original pattern inheritance

I can't seem to find the meaning of this way of inheritance , I don't know what problem it solves with composite patterns ?

1. The basic idea

The idea of prototype inheritance implementation is : Assign the object directly to the prototype of the constructor

2. Implementation method

function object(obj) {
    function F(){};
    //  Assign an object to the prototype of the constructor 
    F.prototype = obj;
    //  return  new  New objects created during 
    return new F();
}
 Copy code 

This object Function creates a temporary constructor , Assign the passed in object to the prototype of the constructor , Then return an instance of the temporary constructor

How can we use it

let student = {name:'xxx'}
let another = object(student)
 Copy code 

We need to prepare a parent object first , That is, the object to be inherited , Then pass in as a parameter object function , The returned object is an object that takes the parent object as the prototype object

image-20210817124252511

3. The problem is

In fact, its problems are the same as those of prototype chain inheritance , Properties and methods are shared

let student = {name:['ljc']}
let one = object(student)
let two = object(student)
one.name.push('aaa')
two.name.push('bbb')
 Copy code 

We give one,two Object name Add attributes to the array , Print it again one.name

image-20210817125947227

This creates the problem of being shared

4. Advantages and disadvantages

advantage :
  • Compatibility is good. , Simple
  • You don't need to create constructors alone
shortcoming :
  • Multiple instances share inherited properties , There is a situation that has been tampered with
  • Can't pass parameters

ES5 The addition of Object.create() Methods , Can replace the above object Method . It also provides a specification for prototype inheritance

5、 ... and 、 Parasitic inheritance

1. The basic idea

Creates a function that simply encapsulates the inheritance process , The function has some way to enhance the object internally , Finally return the object .

That is, on the basis of prototype inheritance Strengthen the object .

2. Implementation method

function createAnother(original) {
    let clone = object(original); //  Inherit an object   Return new function 
    clone.sayHi = function () {
        console.log('hi');
    }; 
    return clone; //  Return this object 
}
 Copy code 

In this code , It seems that only on the basis of the original object , Added a method to the object , And encapsulated into a function , For our direct use

3. Advantages and disadvantages

advantage :
  • Just focus on the object itself , Don't care about types and constructors
shortcoming :
  • Functions are difficult to reuse
  • Multiple instances share inherited properties , There is a situation that has been tampered with
  • Cannot pass parameter

6、 ... and 、 Parasitic combination inheritance

Combinatorial inheritance still has the problem of efficiency , The main problem is , The parent constructor is always called 2 Time

1. The basic idea

Combine composite inheritance and parasitic inheritance to reduce the number of calls to the parent class , So as to achieve the goal

2. Implementation method

In the method of combinatorial inheritance, we call Once , also new Once , Causes the call to 2 Secondary parent class , And in parasitic inheritance , We can call API To implement the prototype of inheriting the parent class

We combine the two

No longer use new Keywords to change the prototype

function Father() {
    this.a = [1, 2, 3, 4]
}
Father.prototype.say = function () {
    console.log(111);
}
function Son() {
    Father.call(this)
}
Son.prototype = Object.create(Father)
let son1 = new Son()
let son2 = new Son()
 Copy code 

use Object.create To override the prototype of a subclass , This reduces calls to the parent class

At this time, we print on the console son1 You will find that the problem has been solved

image-20210817174003097

3. The problem is

In this way , There are also some problems , When there are methods on our subclass prototype

These methods will be lost because the prototype is rewritten

Let's add a... At the top of the code sayHi Method

Son.prototype.sayHi = function() {
	console.log('Hi')
}
 Copy code 

image-20210817174246873

To solve this problem , In fact, it can be in After the prototype is rewritten Then add the method of subclass prototype

4. Advantages and disadvantages

advantage :
  • It's basically the best inheritance scheme , And, of course, the Grail inheritance

  • The parent constructor was called only once , Save performance .

  • Avoid generating unnecessary attributes

shortcoming :
  • Subclass prototypes are overridden

That's what I'm talking about ES5 Medium 6 There are two ways of inheritance

ES6 Inheritance in

because ES6 Previous inheritance was too complex , Too much code , Again ES6 A new inheritance method is introduced in extends Inherit

use extends Keyword to implement inheritance

class Father {}
class Son extends Father {
    constructor() {
        super()
    }
}
 Copy code 

In this way, the subclass inherits the parent class , The key here is to be in the subclass constructor Add a super keyword

It should be noted that

In subclass constructor Must be referenced in method super Method , Otherwise, the new instance will report an error , This is because of the subclass itself this object , must Through the first The parent constructor completes the plasticity , Get the properties and methods of the parent class

Then add the subclass's own properties and methods

without super Method , Subclasses don't have this object , You're going to report a mistake

image-20210817194042644

About class There's a lot more , Not much here

reference

《JavaScript Advanced programming 》

《JavaScript There are eight common inheritance schemes 》


That's about JS Implementing inherited 7 There's a way , Of course, there are other inheritance methods , The Grail pattern inherits , Copy, inheritance and so on

That's all of this , I hope you like , If you have any questions, you can leave a message in the comment area ~

copyright notice
author[Xiao Cheng],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2021/08/20210827084141580s.html

Random recommended