Common ways of inheritance for JavaScript

Keywords: Javascript Attribute

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;

Posted by balistic on Sun, 21 Jul 2019 19:33:03 -0700