Javascript inheritance scheme

1. Prototype chain inheritance

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 stereotype chain inherits the core: an instance of a parent class is the stereotype of a subclass.

The essence of inheritance is copying, that is, rewriting a prototype object and replacing it with an instance of a new type,

function Foo(name){ this.color = ['red','blue','black'] this.name = name }; Foo.prototype.sayName = function () { return ('my name is '+this.name) } function Car(age){ this.age = age } Car. Prototype = new Foo('jack') a = new Car(16) b = new Car() b.color.push('white' console.log(a.name,a.age) console.log(a.color,a.sayName())Copy the code

When we print the color property of instance A, we accidentally find an extra white because in the inheritance of the prototype chain,Reference types are shared by all instances, and multiple instances’ operations on reference types are tampered with. Rather than being a separate part of it,

This is also the problem with prototype chain inheritance:

Problem 1: Reference type attributes contained in the stereotype will be shared by all instances;

Problem 2: A subclass cannot take arguments to its parent constructor when instantiated.

So we came up with the constructor inheritance method

2. Borrow constructor inheritance

Basic idea:

The basic idea behind borrowing constructors is to use call or apply to copy (borrow) the properties and methods specified by this from the parent class into instances created by subclasses. Because this object is bound at run time based on the execution environment of the function. That is, globally, this equals window, and when a function is called as a method of an object, this equals that object. The Call, apply methods change the object context of a function from the original context to the new object specified by thisObj.

If you don’t know what this refers to, take a closer look at the full explanation of this

This points to a super detailed solution to the problem

function SuperType(){ this.colors = ["red", "blue", "green"]; } SuperType. Prototype. GetColor = function () {return this. Colors} function SubType () {/ / inherited the SuperType SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); console.log(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); console.log(instance2.colors); //"red,blue,green" instance2.getColor() TypeError: instance2.getColor is not a functionCopy the code

When we try to use a method from the parent stereotype, we can’t find getColor if we follow the stereotype chain. This is because instances of subclasses do not inherit stereotype attributes/methods

Core: Using the constructor of the parent class to enhance the instance of the child class is equivalent to copying the instance properties of the parent class to the child class (without using the stereotype).

Disadvantages: Methods are defined in constructors, can only inherit the instance attributes and methods of the parent class, can not inherit the prototype attributes/methods, function reuse cannot be realized, each subclass has a copy of the parent class instance function, affecting performance

3. Combinatorial inheritance

Principle: Use the prototype chain to achieve the inheritance of prototype attributes and methods, using the constructor to achieve the inheritance of instance attributes. The combination of stereotype inheritance and constructor inheritance methods is optimized to achieve a method that can inherit the stereotype and reference types are not shared by all instances.

function Person (name) { this.name = name; This. Friends = [' xiao Li ',' xiao Hong ']; }; Person.prototype.getName = function () { return this.name; }; Function Parent (age) {Person. Call (this,' old Ming '); // Call the constructor this.age = age; }; Parent. Prototype = new Person(' old '); Var result = new Parent(24); // Call the constructor console.log(result.name) for the first time; // result.friends.push(" xiaozhi "); // result.friends.push(" xiaozhi "); / / the console. The log (result. Friends); //[' xiao Li ',' Xiao Hong ',' Xiao Zhi '] console.log(result.getName()); / / old Ming console. The log (result. The age); //24 var result1 = new Parent(25); // Each constructor has its own attributes by borrowing, and the common method console.log(result1.name) is enjoyed by the prototype; / / old Ming console. The log (result1. Friends); //[' Xiao Li ',' Xiao Hong ']Copy the code

Advantages:

Prototype chain and borrowed constructor inheritance are combined to learn from each other. Function reuse can be achieved, and ensure that each subclass does not share the parent class reference type attributes.

Disadvantages:

The supertype constructor is called twice: once while the subtype stereotype is being created and once inside the subtype constructor.

4. Parasitic combinatorial inheritance

function inheritPrototype(subType, superType){ var prototype = Object.create(superType.prototype,{}); Prototype. constructor = subType; // Enhance the object to make up for the loss of the default constructor property when overwriting the prototype. Function SuperType(name){this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; Function SubType(name, age){supertype.call (this, name); this.age = age; InheritPrototype (SubType, SuperType); SayAge = function(){alert(this.age); // New subclass.prototype.sayage = function(){alert(this.age); } var instance1 = new SubType("xyc", 23); var instance2 = new SubType("lxy", 23); instance1.colors.push("2"); // ["red", "blue", "green", "2"] instance1.colors.push("3"); // ["red", "blue", "green", "3"]Copy the code

The efficiency of this example is that it calls the SuperType constructor only once, and thus avoids creating unnecessary, redundant properties on subtype. prototype. At the same time, the prototype chain stays the same; As a result, instanceof and isPrototypeOf(), which are the most mature methods and are now implemented by libraries, can also be used normally

Five, the class

In ES6, the class keyword is officially given to implement object-oriented style writing, but is essentially a syntactic sugar for parasitic combinatorial inheritance.

class Person { constructor(age) { this.age_ = age; } sayAge() { console.log(this.age_); Return new Person(math.floor (math.random ()*100)); return Person(math.floor (math.random ()*100)); }} class Doctor extends Person {} const Doctor = new Doctor(32); doctor.sayAge(); / / 32Copy the code

conclusion

1.ES5 inheritance essentially creates the instance object of the subclass and then adds the methods of the Parent class to this (parent.apply (this)).

2.ES6 has a completely different inheritance mechanism, essentially creating an instance object of the superclass, this (so the super() method of the superclass must be called first), and then modifying this with the constructor of the subclass.

3. Inheritance of ES5 is implemented through the prototype or constructor mechanism.

4.ES6 defines classes using the class keyword, which contains constructors. Classes inherit from each other using the extends keyword.

Juejin. Cn/post / 684490…