Introduction to the

After the Chinese New Year, I came back. To be honest, I’ve almost forgotten everything I learned. Uncomfortable ah, in order to return to the original state, today bear a restless heart to tell you about the object inheritance in JS, and explain the disadvantages of the prototype chain mentioned last time. (For those who don’t know, check out my last article about prototypes and prototype chains.)

The following is a reference to chapter 6 of Object-Oriented programming in JavaScript Advanced Programming (version 3).

inheritance

What is inheritance? To put it simply, if object A inherits object B, then object A has all the properties and methods of object B. Your father’s property will pass to you, and you will own all your father’s property. Let’s do it in code.

Prototype chain inheritance
Function Parent() {this.money = 1000; } Parent.prototype.getMoney = function() { console.log(this.money); Prototype = new Parent(); function Child() {} Child.prototype.constructor = Child; // declare a subclass instance let child1 = new Child(); console.log(child1.money); //1000 child1.getMoney(); / / 1000Copy the code

Let’s look at a picture to illustrate

The code above is typical of a prototype chain inheritance. We change the pointer of the Child constructor to point to the parent instance, so that child1 instance can get the parent prototype method getMoney and the parent instance property Money through the prototype chain. As if there were no problems, subclasses inherit the attributes and methods of their parent class perfectly. But is that really the case? Let’s talk about the disadvantages of prototype chain inheritance. Go straight to code

Function Parent() {this.money = 1000; this.colors = ["red", "blue"]; } / / to the Parent class constructor add a method on the prototype of the Parent. The prototype. GetMoney = function () {the console. The log (enclosing money); Prototype = new Parent(); function Child() {} Child.prototype.constructor = Child; // declare a subclass instance let child1 = new Child(); child1.colors.push("yellow"); console.log(child1.colors); //["red", "blue", "yellow"] let child2 = new Child(); console.log(child2.colors); //["red", "blue", "yellow"]Copy the code

Since all Child instances refer to the same Parent instance, a modification of the reference type attribute on Parent by one Child instance changes the reference type attribute on all Child instances. Second, when creating instances of subtypes, we cannot pass arguments to the parent type. Constructor inheritance comes next, which may solve some of our problems.

Constructor inheritance
Function Parent(colors) {this.colors = [colors]; } / / to the Parent class constructor add a method on the prototype of the Parent. The prototype. GetColors = function () {the console. The log (enclosing colors); } // This is the subclass constructor, which calls the superclass constructor in the subclass constructor, and applies the attributes and methods of the superclass to the subclass instance. function Child(... colors) { Parent.apply(this, colors); } let child1 = new Child(["red", "blue", "yellow"]); console.log(child1.colors); / / / "red", "blue", "yellow"] / / again let a subclass instance declaration child2 = new Child ([" red ", "blue"]); console.log(child2.colors); //["red", "blue"] child1.getColors(); TypeError child1.getColors is not a function child2.getColors(); // TypeError child2.getColors is not a functionCopy the code

Again, the picture:

The inheritance way perfect solved the problem of the prototype chain above inherit legacy, * * when new subclass constructor in the subclass constructor calls the superclass constructor, will be a member of the superclass constructor properties and methods are bound to the subclass constructor of this, both to avoid multiple subclass instance Shared between a prototype instance, You can also pass parameters to the parent constructor. This is a general disadvantage of constructors. As mentioned in the previous article, creating the same method on every instance is unnecessary and wastes memory space. The second drawback is that you can’t get the properties and methods on the superclass stereotype.

Each of the above two ways of succession has its own strengths, so can we take their strengths? Indeed, there is a new method of inheritance —- combinatorial inheritance.

Combinatorial inheritance
Function Parent(... colors) { this.colors = [...colors]; } / / to the Parent class constructor add a method on the prototype of the Parent. The prototype. GetColors = function () {the console. The log (enclosing colors); } // This is the subclass constructor, which calls the superclass constructor in the subclass constructor, and applies the attributes and methods of the superclass to the subclass instance. function Child(... Colors) {// This is the second call to the Parent constructor parent.apply (this, colors); } // This is the first call to the Parent constructor child.prototype = new Parent(); Child.prototype.constructor = Child; // declare a subclass instance. Let child1 = new Child("red", "blue"); child1.colors.push("yellow"); console.log(child1.colors); //["red", "blue", "yellow"] child1.getColors(); //["red", "blue", "yellow"] let child2 = new Child("red", "blue"); console.log(child2.colors); //["red", "blue"] child2.getColors(); //["red", "blue"]Copy the code

To:

Combinatorial inheritance is an inheritance pattern that combines the prototype chain with the techniques of borrowing constructors to make the best of the two. ** The idea behind this is to use stereotype chains for inheritance of stereotype properties and methods, while borrowing constructors for inheritance of instance properties. In this way, functions can be reused by defining methods on prototypes, while ensuring that each instance has its own attributes. This inheritance calls the superclass constructor twice, once while the subclass prototype is being created and once inside the subclass constructor. Yes, the subtype eventually contains all of the instance properties of the parent object, but we have to override those properties when we call the subtype constructor. ** then added a small improvement, the emergence of parasitic combination inheritance.

Parasitic combinatorial inheritance
Function Parent(... colors) { this.colors = [...colors]; } / / to the Parent class constructor add a method on the prototype of the Parent. The prototype. GetColors = function () {the console. The log (enclosing colors); } // This is the subclass constructor, which calls the superclass constructor in the subclass constructor, and applies the attributes and methods of the superclass to the subclass instance. function Child(... colors) { Parent.apply(this, colors); Prototype = object.create (Parent. Prototype); Child.prototype.constructor = Child; // declare a subclass instance. Let child1 = new Child("red", "blue"); child1.colors.push("yellow"); console.log(child1.colors); //["red", "blue", "yellow"] child1.getColors(); //["red", "blue", "yellow"] let child2 = new Child("red", "blue"); console.log(child2.colors); //["red", "blue"] child2.getColors(); //["red", "blue"]ziCopy the code

Graph:

Parasitic combinatorial inheritance makes a small change in combinatorial inheritance by pointing the prototype of the subclass constructor to a clone of the parent constructor prototype. ** This avoids calling the parent constructor twice. It also prevents the subclass stereotype from being the same object as the superclass stereotype (pointing directly to the superclass stereotype will cause the subclass stereotype to change and may override the methods of the superclass stereotype). ** Like that’s perfect.

conclusion

Js about the above is some different inheritance methods, I hope to help you. If there is any mistake or description is not detailed enough, please help me to point out the mistake. Thank you ha ha ha!