The succession of es5

1. Prototype chain inheritance

function Parent() { this.name = 'kevin'; } Parent.prototype.getName = function () { console.log(this.name); } function Child() {} // VVV Child. Prototype = new Parent(); Var child = new child (); child.getName() //kevinCopy the code

Important: Make the prototype of the new instance equal to the instance of the parent class

Instance inheritable properties: constructor properties of the instance, constructor properties of the superclass, properties/methods of the superclass stereotype. The new instance does not inherit the attributes of the parent instance

Disadvantages: 1. Reference type attributes are shared by all instances.

If you overwrite the original value type attribute with child.name, instead of overwriting the name in the prototype, you create a new name attribute in the child instance’s scope that will be accessed first. But if child.name is a reference value such as an array, then child.name.push() accesses and overwrites the name in the prototype object directly, causing other instances to be affected.

  1. When creating an instance, there is no way to pass arguments to the constructor of the parent type without affecting all instances. (Passing a parameter to a parent class is not a common requirement.)

  2. The constructor property on the prototype object of the subclass constructor has been overridden and no longer refers back to the subclass constructor itself

Constructor inheritance

function Parent() { this.name = ['kevin']; } Parent.prototype.say = function (){ console.log("hello"); } function Child() {// VVV constructor inherits VVV parent.call (this); //^^^ constructor inherits ^^^ ^} var child1 = new Child(); var child2 = new Child(); child1.name.push("cc"); console.log(child2.name); //[" Kevin "] -> Reference type does not share chiild1.say(); //undefined -> methods in the parent prototype cannot be inheritedCopy the code

Important: Use.call() or.apply() to introduce a superclass constructor into a subclass function for ordinary execution

Advantages: Solves the main problem of prototype chain: reference type sharing

Disadvantages:

  1. Only the attributes and methods of the superclass constructor are inherited, not the attributes and methods of the superclass prototype

  2. Methods are defined in constructors, and the parent constructor is called every time an instance is created, wasting performance.

3. Combinatorial inheritance

function Parent() { this.name = ['kevin']; } Parent.prototype.getName = function () { console.log(this.name, this.age); } function Child(age) {//2. this.age = age; } //1. Call Parent() child.prototype = new Parent(); / / to make the Child a prototype object constructor that points back to the Child, of course in a natural object should be equal to the two things is inherently: Child. The prototype. The constructor = Child; var child1 = new Child(19); var child2 = new Child(20); child1.name.push("cc"); Child1. GetName (); / / / "Kevin", "cc" 19 child2. The getName (); //["kevin"] 20Copy the code

Advantages: fusion of the former two, the first prototype chain after the constructor, can pass parameters & reuse

Disadvantages:

1. Disadvantages from constructor integration: every time an instance is created, the parent class constructor will be called in addition to the subclass constructor, which wastes performance.

Note: the description in many articles that the superclass constructor is called twice each time a subclass instance is created is inaccurate. It is actually the same as constructor inheritance, and the subclass and the superclass constructor are called once. Child. Prototype = new Parent(); The parent class is called only once more than the constructor inheritance.

2. The parent class will have a property with the same name (this is the key to optimizing for parasitic combinatorial inheritance, not avoiding calling the parent constructor twice as mentioned in many articles)

What’s the problem with having the same property? To run the example in a browser, type child1:

[[Prototype]] : child1; [Prototype] : child1; [Prototype] : child1;

The first name attribute inherited from the Prototype chain is in child.[[Prototype]], and the second name attribute inherited from the constructor is in the child1 instance. The two are not simply an overlay relationship, but because the priority of access is first searched in the scope of the instance itself, and then in the scope of the prototype object of the instance. So it looks as if the constructor overrides the name property of child1. [[Prototype]] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype] : [Prototype]

Ideally we want child1.[[Prototype]] to have no extra attributes, so we need parasitic inheritance to optimize this part.

4. Original type inheritance

function Parent(){ this.name="kevin"; [[Prototype]] //F is the constructor of the subclass. Function createObj(obj) {function F() {} f.toType = obj; return new F(); } var parent = new Parent(); Var child = createObj(parent); Var child = object.create (parent); console.log(child.name); // Inherits the superclass attributesCopy the code

Child.[[Prototype]] = obj: [Prototype] = obj:

  1. Apis provided by ES5var child = Object.create(obj)

  1. In the example aboveHandwriting implementation methodvar child = createObj(obj)

Important: This method skips the Child constructor entirely and uses a function to return an instance of an object modeled after obj. Obj is often an instance of a parent class. The two methods are slightly different: 1 generates instances belonging to the Parent class, 2 generates instances belonging to the Function class

Advantages: The parent constructor is not called every time you create a Child instance, and the subclass constructor is not called either, in fact there is no child subclass at all

Disadvantages: It has some disadvantages of prototype chain inheritance, reference type attribute sharing, can not pass parameters to the parent class; And not only can’t it pass arguments to the parent class, it can’t even pass arguments to the instance when it’s created, which is something that needs to be addressed by later parasitic inheritance. (Update: Object.create() can take two arguments. The second argument is an Object that defines additional attributes for the new Object, but this second argument is not commonly used.

Parasitic inheritance

Function createObj(o) {var clone = object.create (o); clone.say = function() { console.log(this) }; return clone }Copy the code

Key points: is to give the original type inheritance outside a shell. Encapsulate the original type inheritance again, add new proprietary methods and properties to the object, and return the new object

Advantages: the same as the original type of inheritance advantages, in addition to partially solve the original type of reference type attribute sharing problems, the creation of instance reference problems

Disadvantages: 1. Unable to achieve function reuse. The same subclass internal method is created each time it is instantiated

2. Reference type attributes that are not defined when the instance is created but are only defined in the parent class will still have sharing problems.

Parasitic combinatorial inheritance

Many articles say:

Parasitic combinatorial inheritance is designed to solve the problem that in any case the superclass constructor is called twice: once when the subtype stereotype is created and once inside the subtype constructor. Right

In fact, when a composite inherited subclass is created, the subclass constructor is called once and the parent constructor is called once through constructor inheritance. Parasitic combinatorial inheritance is also called every time a subclass is created: one subclass constructor, one superclass constructor! Therefore, the logic of using parasitic combinatorial inheritance to reduce the number of constructor calls is completely untenable.

So what problem does parasitic combinatorial inheritance solve in combinatorial inheritance? The answer is simple: remove the namesake attribute from the parent class.

Since parasitic combinatorial inheritance is essentially a combination of constructor inheritance and parasitic inheritance, let’s review the shortcomings of both:

Disadvantages of constructor inheritance: You cannot inherit the attributes and methods of the parent class stereotype

Disadvantages of parasitic inheritance: Reference types in parent instances share problems

So the idea of parasitic combinatorial inheritance is very clear, and highlights:

Inheriting attributes and methods of a parent class instance through constructors & inheriting attributes and methods of a parent class prototype through a stereotype chain.

// The parent class is inherited from the parent class. The parent class is not instantiated. Object.create() passes in an instance of the parent class and gets an instance of the subclass. [[Prototype]]; 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() { console.log(this.name); }; Function SubType(name, age) {supertype.call (this, name); this.age = age; } // Replace the inheritPrototype(SubType, SuperType) with the inheritPrototype(SubType, SuperType); Subtype.prototype.sayage = function() {console.log(this.age); subtype.prototype.sayage = function() {console.log(this.age); }; let sub = new SubType('amy',25) console.log(sub);Copy the code

The Parent class does not have the same name.

The appended drawings:

The succession of es6

Class is essentially a function, just a syntactic sugar.

class Parent { constructor(x, y) { this.x = x; this.y = y } getX() { return this.x } } class Child extends Parent { constructor(x, y, name) { super(x, y); // Call the parent class constructor(x,y) this.name = name; } getName() { return this.name } var child1 = new Child("x", "y", "ccg"); console.log(child1); //Child {x: "x", y: "y", name: "ccg"}Copy the code

1. Class implements inheritance through the extends keyword.

2. The super keyword

The super keyword can be used as either a function or an object. In both cases, it’s used quite differently.

In the first case, super, when called as a function, represents the constructor of the parent class. ES6 requires that the constructor of a subclass must execute the super function once.

This situation is similar to ES5 constructor inheritance, except that ES5 creates the Parent class’s instance object this first and then adds the Parent class’s method to this (parent.apply (this)), whereas ES6 creates the Parent class’s instance object this first. So the super keyword must be called.

class A {
  constructor() {
    console.log(new.target.name);
  }
}
class B extends A {
  constructor() {
    super();
  }
}
new A();
new B();
Copy the code

As a function, super can only be in the constructor of a subclass. But as an object, you can point to the parent’s prototype object in a normal method.

Point to a parent class in a static method. (! Since super refers to the parent’s prototype object, methods defined in the parent instance cannot be called by super.

class Parent { static myMethod(msg) { console.log('static', msg); } myMethod(msg) { console.log('instance', msg); } } class Child extends Parent { static myMethod(msg) { super.myMethod(msg); } myMethod(msg) { super.myMethod(msg); }} Child. MyMethod (int x) (1); //static 1 var child = new Child(); Child. MyMethod (int x) (2); //instance 2Copy the code

To use super, specify how to use it explicitly.

class Parent { constructor() { super(); console.log(super); // Error}}Copy the code

Static method of Class

ES6 classes have static methods. The static keyword in front of a method means that the method is not inherited by the instance, but is called directly from the class.

class Food {
static classMethod() {
   return 'hello'
}
}

Food.classMethod() // "hello"

var poo = new Food();
poo.classMethod() // TypeError: poo.classMethod is not a function
Copy the code

Called directly from the class, the output is Hello, cannot be called after instantiation.