Six inheritance ways to quickly distinguish JS

Time:2021-2-24

First, we define a parent class animal, and then use cat class to inherit from this parent class

function Animal (name) {  
 this.name = name || 'Animal';  
 this.sleep = function(){  
 console.log ( this.name  +'sleeping! ');  
 }  
}  
Animal.prototype.eat = function(food) {  
 console.log ( this.name  +'eating:' + food ');  
};

1. Prototype chain inheritance

Core: the prototype object of the subclass is equal to the instance of the parent class (subclass. Prototype = new parent class ())

function Cat(){  

}  
Cat.prototype  =New animal(); // if it is equal to the parent prototype, it will change (point to the same place)  
Cat.prototype.name = 'cat';  
//Test Code  
var cat = new Cat();  
console.log(cat.name);  
console.log(cat.eat('fish'));  
console.log(cat.sleep());  
console.log(cat instanceof Animal); //true   
console.log(cat instanceof Cat); //true

advantage:

  • A very pure inheritance relationship. An instance is an instance of a subclass as well as an instance of a parent class
  • A new prototype method / prototype property is added to the parent class, which can be accessed by all subclasses
  • Simple and easy to implement

Disadvantages:

  • Cannot implement multiple inheritance
    Only one direct parent class can be inherited, because prototype points to the instance of the parent class and cannot inherit methods on the prototype chain of other classes
  • Reference properties from prototype objects are shared by all instances
  • When creating a subclass instance, parameters cannot be passed to the parent class constructor

2. Construction inheritance

Core: using the constructor of the parent class to obtain the properties and methods of the subclass is equivalent to copying the instance properties of the parent class to the subclass (parent class. Call (this))

function Cat(name){  
 Animal.call(this);  
 this.name = name || 'Tom';  
}  
   
// Test Code  
var cat = new Cat();  
console.log(cat.name);  
console.log(cat.sleep());  
console.log(cat instanceof Animal); // false  
console.log(cat instanceof Cat); // true

advantage:

  • Solved the problem that the subclass instances share the reference properties of the parent class in 1 (not prototype)
  • When you create a subclass instance, you can pass parameters to the parent class
  • It can implement multiple inheritance (call multiple parent objects)
  • An instance is not an instance of a parent class, but an instance of a subclass
  • Only instance properties and methods of the parent class can be inherited, not prototype properties / methods
  • Function reuse cannot be realized. Every subclass has a copy of the parent class instance function, which affects the performance

3. Archetypal inheritance

Core: the prototype inherited object method is essentially a shallow copy of the parameter object.

function Cat(o){
  function F(){}
  F.prototype = o;
  return new F();
}

let cat = object(person);
cat.name = "Bob";
anotherPerson.friends.push("Rob");

Advantage: the parent method can be reused
Disadvantages: the reference property of the parent class will be shared by all instances of the subclass. When the subclass builds an instance, it will not be able toParameters cannot be passed to a parent class
ECMAScript 5 through the new Object.create The () method normalizes prototype inheritance. This method takes two parameters: an object to be used as the prototype of the new object and (optional) an object to define additional properties for the new object. In the case of passing in a parameter, Object.create The () method behaves the same as the object () method. So the above code can be transformed into
let cat = Cat(Animal); => let cat = Object.create(Animal);

4. Copy inheritance

Core: subclass. Prototype. Attribute = new parent (). Attribute

function Cat(name){  
 var animal = new Animal();  
 for(var p in animal){  
 Cat.prototype[p] = animal[p];  
 }  
 Cat.prototype.name = name || 'Tom';  
}  
   
// Test Code  
var cat = new Cat();  
console.log(cat.name);  
console.log(cat.sleep());  
console.log(cat instanceof Animal); // false  
console.log(cat instanceof Cat); // true

advantage:

  • Support multiple inheritance

Disadvantages:

  • Low efficiency and high memory consumption (because the properties of the parent class need to be copied)
  • Unable to get the parent class’s non enumerable method. The method on the prototype can be obtained (non enumerable method, can’t be accessed with for in): you need to manually set the enumerable to false:Object.defineProperty () and symbol ()) Object.keys () cannot get the Object.getOwnPropertyNames () it can’t be traversed on the prototype, and it can be traversed both by itself and by itself

5. Combinatorial inheritance(prototype, a combination of constructor inheritance)

Core: by calling the parent class construction, inherit the properties of the parent class and retain the advantages of parameter passing, and then realize function reuse (parent class. Call (this), child class. Prototype = new parent class ()) by taking the parent class instance as the subclass prototype

function Cat(name){  
 Animal.call(this);  
 this.name = name || 'Tom';  
}  
Cat.prototype = new Animal();  
   
// Test Code  
var cat = new Cat();  
console.log(cat.name);  
console.log(cat.sleep());  
console.log(cat instanceof Animal); // true  
console.log(cat instanceof Cat); // true

advantage:

  • You can inherit instance properties / methods or prototype properties / methods (prototype inheritance)
  • Is an instance of both a subclass and a parent (prototype chain)
  • No reference property sharing problem (constructor inheritance)
  • Transitive parameters (constructor inheritance)
  • Function reusability (prototype chain inheritance)

Disadvantages:

  • Call the parent class constructor twice and generate two instances (the subclass instance shields the one on the subclass prototype)

6. Parasitic combinatorial inheritance

In this way, when calling the construction of the parent class twice, the instance method / attribute of the parent class will not be initialized twice, so as to avoid the disadvantages of combinatorial inheritance (parent class. Call (this). Var super = function() {}), Super.prototype= Parent class. Prototype, child class. Prototype = new super)

function Cat(name){  
 Animal.call (this); // methods and properties of the instance  
 this.name = name || 'Tom';  
}  
(function(){  
 //Create a class without instance methods  
 var Super = function(){};  
 Super.prototype = Animal.prototype;  
 //Prototype instances as subclasses  
 Cat.prototype = new Super();  
})();  
   
// Test Code  
var cat = new Cat();  
console.log(cat.name);  
console.log(cat.sleep());  
console.log(cat instanceof Animal); // true  
console.log(cat instanceof Cat); //true

advantage:

  • perfect

Disadvantages:

  • The implementation is complex

Supplement: ES6 inheritance

Class subclass extends superclass {constructor() {super()}}

class Cat extends Animal {  
 constructor(name,food){  
 //Call the constructor (name) of the parent class  
 super(name);   
 this.food = food  
 }  
 eat(food){  
 //Call the method of the parent class  
 super.eat(food);   
 }  
}  
​  
// Test Code  
var cat = new Cat();  
console.log(cat.name);  
console.log(cat.sleep());  
console.log(cat instanceof Animal); // true  
console.log(cat instanceof Cat); //true