There are seven main inheritance modes in JavaScript: prototype chain inheritance, constructor inheritance, combination inheritance, prototype inheritance, parasitic combination inheritance, and inheritance of multiple objects.
1: Prototype chain inheritance (core: prototype parent class instances as subclasses)
Basic concept: Rewrite the prototype object and give it an instance of a new object.The basic idea is to have one prototype object point to an instance of another parent class.
function Super() { //Basic data types this.text = 'Hello'; } Super.prototype.getSuperText = function() { return this.text; } function Sub() { this.subText = 'Word'; } Sub.prototype = new Super(); const instance = new Sub(); console.log(instance);
Features: Very pure inheritance relationship, instances are instances of subclasses as well as instances of parent classes.Parent class adds prototype methods or attributes that can be accessed by subclasses.
Advantages: Simple and easy to operate
Disadvantages: Operations on reference type data can affect each other (between multiple instances)
function Super() { //Complex object, that is, reference type this.value = [1, 2, 3, 4]; } Super.prototype.getSuperValue = function() { return this.value; } function Sub() { this.subText = 'Word'; } Sub.prototype = new Super(); const instance1 = new Sub(); const instance2 = new Sub(); instance1.value.push(5); console.log(instance2.value); // (5) [1, 2, 3, 4, 5]
2: Constructor Inheritance
//Define Constructor function Super(){ this.value = [1, 2, 3, 4]; } //New attribute getSuperValue Super.prototype.getSuperValue = function() { return this.value; } //SubRe-invoke every execution function Sub(){ Super.call(this); } const instance1 = new Sub(); instance1.value.push(5); console.log(instance1.value); // (5) [1, 2, 3, 4, 5] const instance2 = new Sub(); console.log(instance2.value); // (4) [1, 2, 3, 4]
Features of the constructor: (has no effect on the reference data type) The code output above is instance1 1, 2, 3, 4, 5, and instance2 is 1, 2, 3, 4.This is because the subcalls a super.call() again each time it executes, and the constructor creates a new object each time it builds the object, so each call to the subexecutes the super once, and each execution requests a new memory space, resulting in two value sIs not the same and does not affect each other.
Disadvantages: The above code does not use the properties of proto and prototype throughout the base process of the constructor, and if not, the prototype chain is not connected.Therefore, the constructor base can only inherit instance properties and methods of the parent class, not properties and methods on the prototype chain.
3: Combinatorial Inheritance
By calling a parent class construct, inherits the properties of the parent class and preserves the advantages of passing parameters, then reuses functions by prototyping parent instances as subclasses.
The advantages of constructor inheritance and prototype chain inheritance are preserved.However, Person was executed twice, and the attribute was duplicated.
function Person(name) { this.name = name; this.value = ["head", "body", "legs"]; } Person.prototype.getName = function() { return this.name; }; // Constructor Inheritance function Teacher(name, school){ // Execute another Person Person.call(this, name); this.school = school; } // Prototype Chain Inheritance // Execute Person once Teacher.prototype = new Person(); const Eric = new Teacher("Eric",27); Eric.getName(); // Output: Eric // prototype constructor refers back to itself Teacher.prototype.constructor = Teacher; Teacher.prototype.getSchool = function() { return this.school; };
Features: You can inherit both instance properties and methods as well as prototype properties and methods.Instances of both subclasses and parent classes do not have the problem of referencing attribute sharing.Parameters can be passed and functions can be reused.
Disadvantages: Two calls to the parent constructor resulted in two instances.
4: Prototype Inheritance
Prototypes allow you to create new objects based on existing objects without creating custom types.
Principle: (Essentially) Use an empty object as an intermediary.
const lakers = { name: "lakers", value: ["Micheal", "Wade", "Kobe"] }; const lakers1 = Object.create(lakers); const lakers2 = Object.create(lakers); lakers1.value.push('Fish'); console.log(lakers);
Simulate Object.create()
object.create() principle: wrap an object with a function, and then return the call to the function, which becomes an instance or object with arbitrary properties.
Object.prototype.create = function(obj) { function Fun() {} Fun.prototype = obj; return new Fun(); }
There are two drawbacks: the first is that parameters cannot be passed, and the second is that reference types are contaminated by variables.
5: Parasitic Inheritance
The idea of parasitic inheritance is similar to that of parasitic constructors and factory patterns, which create a function that encapsulates the inheritance process only.
Objective: On the basis of prototype inheritance, new methods and attributes are added to parasitism.
It is characterized by the inability to pass parameters, just like prototype inheritance, and the data types referenced are prone to style contamination.
Object.createNew()
Object.prototype.createNew = function(obj){ var newObj = Object.create(obj); //Get length equal to a function newObj.getLength = function(){ ... }; return newObj; }
6: Parasitic combination inheritance
Objective: To solve the problem of duplicating data twice.
Super executes only once.
//Define Super Constructor function Super(name) { this.name = name; this.value = ["Hello", "Word"]; } //Add a getName to the super prototype chain Super.prototype.getName = function() { return this.name; }; //Define Sub function Sub(name, age) { //Call Constructor Inheritance Super.call(this, name); this.age = age; } let prototype = Object.create(Super.prototype); prototype.constructor = Sub; Sub.prototype = prototype; Sub.prototype.getAge = function(){ return this.age; } const instance1 = new Sub("Eric", 23); const instance2 = new Sub("Vico", 23); instance1.value.push("!"); instance2.value.push("!!");
7: Inherit multiple objects
With prototype inheritance Object.create we get SuperClass, which is the parent class, assign it to ClassOne after we get the prototype of the parent class, then we use an Object.assign for the prototype of ClassTwo, a copy of the object, copy it into ClassOne, and finally ClassOne.prototype.constructor equals ClAssOne.
That is, use a Class.assign to make a copy of the prototype of all the parent classes we want to inherit, then assign it to the object.
function ClassOne.prototype = Object.create(SuperClass.prototype); Object.assign(ClassOne.prototype, ClassTwo.prototype); ClassOne.prototype.constructor = ClassOne;