Several ways in which JavaScript implements inheritance

As a weakly typed object-oriented language, JS inheritance is also one of its very powerful features

Start by defining a parent class

/ / define a Animal function Animal (name) {/ / attribute this. Name = name | | 'Animal'; This.sleep = function(){console.log(this.name + 'sleeping! '); } // animal.prototype. eat = function(food) {console.log(this.name + 'eating:' + food); };Copy the code

Prototype chain inheritance

Core: Use an instance of a parent class as a prototype for a subclass

function Dog(name) {
  / / property
  this.name = name || 'Dog';
}
Dog.prototype = new Person();
var dog = new Dog();
console.log(dog.name); // Dog
console.log(dog.eat('bone'));//Dog is eating: bone
console.log(dog.sleep());//Dog is sleeping
console.log(dog instanceof Animal); //true 
console.log(dog instanceof Dog); //true
Copy the code

Advantages:

  1. Very pure inheritance, an instance is an instance of a subclass and an instance of a parent class
  2. New stereotype methods/attributes in the parent class that are accessible to all subclasses
  3. Simple and easy to implement

Disadvantages:

  1. Creating a subclass instance cannot pass arguments to the superclass constructor
  2. Single inheritance, can not achieve multiple inheritance
  3. All instances of subclasses share the attributes of their parent instance. All properties of the stereotype object are shared by all instances, and when one instance modifies the stereotype properties, the stereotype properties of the other instances are also changed.

Constructor inheritance

Core: Use.call() and.apply() to enhance the parent class’s constructor, which copies the parent class’s instance properties to the child class (without using the stereotype).

function Cat(name, age){
  Animal.call(this, name); // Copy the parent instance attributes to the subclass
  this.age = age || 5;
}

var cat = new Cat("Tom".18);
console.log(cat.name); // Tom
console.log(cat.age); / / 18
console.log(cat.sleep()); // Tom is sleeping
console.log(cat.eat("fish")); // Uncaught TypeError: cat.eat is not a function
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
Copy the code

Advantages:

  1. Inherits only the properties, methods of the parent constructor. There are no attributes and methods inherited from the superclass stereotype.
  2. The shortcoming of prototype chain inheritance is solved
  3. Multiple inheritance (that is, you can inherit multiple constructor properties and call multiple constructors in a subclass constructor)
  4. It is possible to pass arguments to a parent instance from a child instance

Disadvantages:

  1. An instance is not an instance of a parent class, only an instance of a subclass.
  2. Only instance properties and methods of the parent class can be inherited, not stereotype properties/methods.
  3. Function reuse is not possible, each subclass has a copy of the parent class instance function, affecting performance

Combinatorial inheritance (stereotype chain inheritance + constructor inheritance) (common)

Core: Inherits the attributes of the parent class and retains the advantages of passing arguments by calling the parent class constructor, and then implements function reuse by using the parent class instance as a subclass prototype

function Rabbit(name, age) {
  Animal.call(this, name); // Constructor inheritance, second call
  this.age = age || 5;
}
Rabbit.prototype = new Animal(); // Prototype inheritance is called for the first time
Cat.prototype.constructor = Cat; // The emphasis on composite inheritance also needs to be fixed to the constructor point.


var rabbit = new Rabbit("jine");
console.log(rabbit.name); // jine
console.log(rabbit.age); / / 5
console.log(rabbit.sleep()); // Jine is sleeping
console.log(rabbit.eat("carrot")); // Carrot is eating carrot
console.log(rabbit instanceof Animal); // true
console.log(rabbit instanceof Rabbit); // false
Copy the code

Advantages:

  1. The constructor defect is remedied. You can inherit instance properties/methods as well as stereotype properties/methods
  2. Can pass the cords
  3. Function reuse
  4. Constructor properties introduced by each subclass instance are private. There is no reference property sharing problem
  5. Both an instance of a subclass and an instance of a superclass

Disadvantages:

  1. The parent constructor is called twice, generating two instances (memory loss), and the subclass constructor replaces the parent constructor on the prototype.

Primary inheritance

Core: Wrap an object with a function and return a call to that function. This function becomes an instance or object to which properties and methods can be added at any time. Object.create() works this way. In essence, CreateObject() makes a shallow copy of the object passed into it

function CreateObject(obj) {
    var Fun = function() {};
    Fun.prototype = obj; // obj.__proto__===Object.prototype true; Fun.prototype.constructor === Object true
    return new Fun();
}

var person = {
    name: "xiaoming".friend: ["lily"."xiaohong"]}var person1 = CreateObject(person);
var person2 = CreateObject(person);
Person. name does not change after person1.name is changed because person.name is a base type, not a reference type.
person1.name = "xiaohe"; 
console.log(person2.name); //"xiaoming"
console.log(person.name); //"xiaoming"
// Since person.friend is a reference type, person1.friend changes both the current reference type address and the value of person and person2.
person1.friend.push("xiaozhang"); 
console.log(person2.friend); // [" Lily ", "xiaohong", "Xiaozhang "]
console.log(person.friend);// [" Lily ", "xiaohong", "Xiaozhang "]
person1.friend = ["xiaowang"]; // Point the friend attribute of Person1 to another reference address.
console.log(person2.friend); // [" Lily ", "xiaohong", "Xiaozhang "]
console.log(person.friend);// [" Lily ", "xiaohong", "Xiaozhang "]
//person1.friend reference refers to a memory address different from person, person2, so person2 and Person friend attributes do not change.
person1.friend.push("xiaoli");
console.log(person1.friend); // ["xiaowang", "xiaoli"]
console.log(person2.friend); // [" Lily ", "xiaohong", "Xiaozhang "]
console.log(person.friend);// [" Lily ", "xiaohong", "Xiaozhang "]
Copy the code

Advantages: Type and a copy of an object, wrapped in a layer of functions

Disadvantages:

  1. Attributes that contain a reference type value always share the corresponding value
  2. Reuse cannot be achieved. (New instance attributes are added later)

Parasitic inheritance

Core: is to give the original type inheritance around a shell, you can add properties and methods to the shell

// This constructor has the same effect as object.create ()
function CreateObject(obj) {
    var Fun = function() {};
    Fun.prototype = obj; 
    return new Fun();
}

var person = {
    name: "xiaoming".friend: ["lily"."xiaohong"]}function CreatChild(obj) {
    // Create an Object, or use var newObj = object.create (obj);
    var newObj = CreateObject(obj); 
    newObj.sayName = function() { // Enhance objects
        console.log(this.name);
    }
    return newObj;
}

var child1 = CreatChild(obj);
child1.sayName(); // xiaoming
child1.name="xiaohua";
child1.sayName(); // xiaohua

Copy the code

Advantages: No custom type is created, because only a shell returns an object. Objects can be enhanced. Disadvantages: No prototypes, no reuse of properties and methods.

Parasitic combinatorial inheritance

Core: By parasitic way, the instance attributes of the parent class are cut off, so that when the constructor of the parent class is called twice, the two instance methods/attributes are not initialized, avoiding the disadvantages of combinative inheritance

// Attributes are inherited by borrowing constructors, and methods are inherited by a mashup of prototype chains. Essentially, you use parasitic inheritance to inherit the stereotype of the supertype and then assign the result to the stereotype of the subtype
function Person(name){
     this.name = name;
     this.colors = ["red"."green"."blue"];
}
Person.prototype.sayName = function(){
      console.log(this.name);
};
function Child(name,age){
     Person.call(this,name); // Constructor inheritance
     this.age = age;
}
(function(){
    // Create a copy of the supertype stereotype
    var anotherPrototype = Object.create(Person.prototype);
    // Reset the default constructor property lost by rewriting the prototype
    anotherPrototype.constructor = Child;
    // Assign the newly created object to the prototype of the subtypeChild.prototype = anotherPrototype; }) (); Child.prototype.sayAge =function(){
     console.log(this.age);
};
var child1 = new Child("luochen".22);
child1.colors.push("purple");
console.log(child1.colors);      // "red,green,blue,purple"
child1.sayName();
child1.sayAge();

var child2 = new SubType("tom".34);
console.log(child2.colors);      // "red,green,blue"
child2.sayName();
child2.sayAge();
Copy the code

Important: Fixed a problem with composite inheritance.

Examples of inheritance

Core: Adds new features to the parent class instance and returns it as a subclass instance

function Cat(name){ var instance = new Animal(); instance.name = name || 'Tom'; return instance; } var cat = new Cat(); console.log(cat.name); // Tom console.log(cat.sleep()); Console. log(cat instanceof Animal); // Tom is sleeping console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // falseCopy the code

Disadvantages:

  1. An instance is an instance of a parent class, not a subclass
  2. Multiple inheritance is not supported

Copies of the inheritance

Core: Copies the attributes of the parent class in the subclass constructor onto the prototype object of the subclass constructor.

function Cat(name){ var animal = new Animal(); for(var p in animal){ Cat.prototype[p] = animal[p]; } this.name = name || 'Tom'; } var cat = new Cat(); console.log(cat.name); // "Tom" console.log(cat.sleep()); Console. log(cat instanceof Animal); // Tom is sleeping console.log(cat instanceof Animal); // false console.log(cat instanceof Cat); // trueCopy the code

Advantages: Supports multiple inheritance

Disadvantages:

  1. Low efficiency and high memory footprint (due to copying parent class attributes)
  2. Unable to get non-enumerable methods of the parent class (non-enumerable methods, not accessible using for in)

ES6 Class syntax sugar inheritance

class Person {
    constructor(name) {
        this.name = name||"default name";
    }
    reName(name) {
        this.name = name;
    }
}
class Child extends Person {
    constructor(name) {
        super(name);
    }
}
var child1 = new Child();
console.log(child1.name); // default name
child1.reName("Tom");
console.log(child1.name); // Tom
Copy the code