The implementation of JS inheritance

To implement inheritance, we need to have a parent class that looks like this:

/ / 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

1. Prototype chain inheritance

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

function Cat(){ 
}
Cat.prototype = new Animal();
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
Copy the code

Features:

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

Disadvantages:

  • To add attributes and methods to subclasses, add instance attributes to Cat instances in the Cat constructor. If new prototype properties and methods are added, they must be executed after statements like new Animal().
  • Multiple inheritance cannot be implemented
  • Reference properties from the stereotype object are shared by all instances
  • Cannot pass arguments to the parent constructor when creating a subclass instance

Example:

The function Animal (name) {/ / attribute this. Name = name | | 'Animal'; This.sleep = function(){console.log(this.name + 'sleeping! '); } // This. Features = []; } function Cat(name){ } Cat.prototype = new Animal(); var tom = new Cat('Tom'); var kissy = new Cat('Kissy'); console.log(tom.name); // "Animal" console.log(kissy.name); // "Animal" console.log(tom.features); // [] console.log(kissy.features); // [] tom.name = 'Tom-New Name'; tom.features.push('eat'); Console. log(tom.name); // "Tom-New Name" console.log(kissy.name); // "Animal" // Changes to the parent class instance reference type member will affect other subclass instances console.log(Tom.features); // ['eat'] console.log(kissy.features); // ['eat']Copy the code

Cause analysis:

Key point: the attribute lookup process

Execute tom.featues.push, first find the instance property of Tom object (not found), then go to the prototype object, which is the instance of Animal. If yes, insert values directly into the features property of the object.

In the console. The log (kissy. The features); From time to time. Ditto, not on the Kissy instance, so look for the prototype.

If it exists in the prototype, return it, but note that the features property value in the prototype object has changed.

2. Structural inheritance

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).

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
Copy the code

Features:

  • Fixed the problem of subclass instances sharing parent class reference attributes in 1
  • When you create a subclass instance, you can pass parameters to the parent class
  • Multiple inheritance can be implemented (call multiple parent objects)

Disadvantages:

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

3. Instance 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;
}

// 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); // false
Copy the code

Features:

There is no limit to how the call is made, and whether a new subclass () or subclass () returns an object with the same effect

Disadvantages:

  • An instance is an instance of a parent class, not a subclass
  • Multiple inheritance is not supported

Copy inheritance

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
Copy the code

Features:

Support for multiple inheritance

Disadvantages:

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

5. Combinatorial inheritance

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 Cat(name){ Animal.call(this); this.name = name || 'Tom'; } Cat.prototype = new Animal(); // Combinatorial inheritance also needs to be fixed. Cat.prototype.constructor = Cat; // 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); // trueCopy the code

Features:

  • To remedy the weakness of approach 2, you can inherit instance properties/methods as well as stereotype properties/methods
  • Both an instance of a subclass and an instance of a superclass
  • There is no reference property sharing problem
  • Can pass the cords
  • Function reuse

Disadvantages:

The parent constructor is called twice, generating two instances (the subclass instance hides the subclass prototype)

6. Parasitic combination 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

function Cat(name){ Animal.call(this); this.name = name || 'Tom'; } (function(){var Super = function(){}; Super.prototype = Animal.prototype; Cat.prototype = new Super(); Cat.prototype.constructor = Cat; }) (); // 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); //trueCopy the code

Features:

perfect

Disadvantages:

Implementation is complicated