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.
-
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.)
-
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:
-
Only the attributes and methods of the superclass constructor are inherited, not the attributes and methods of the superclass prototype
-
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:
- Apis provided by ES5 :
var child = Object.create(obj)
- In the example aboveHandwriting implementation method :
var 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.