JavaScript Design Patterns--Implementation and Principles of Multiple Inheritance Modes

The original text is from my personal blog site: https://www.dzyong.com (Welcome to)

Link address for this article: https://www.dzyong.com/#/View... (Please label source for reload)

What is inheritance

Inheritance is a concept in object-oriented software technology.If one category A "inherits" from another category B, it is called a "sub-category of B", and B is also called a "parent category of A" or a "superclass of B".Inheritance allows subcategories to have various properties and methods of the parent class without having to write the same code again.While having subcategories inherit the parent category, you can redefine some properties and override some methods, that is, override the original properties and methods of the parent category to achieve functionality different from that of the parent category.Adding new attributes and methods to subcategories is also a common practice.
In general, static object-oriented programming languages, inheritance is static, meaning that the behavior of subcategories is determined at compile time and cannot be expanded at execution time

Now that you know what inheritance is, let's look at six ways to implement inheritance in JavaScript

Prototype Object of Subclass--Class Inheritance

let superClass = function(){
        this.superVal = true
        this.books = ['a', 'b', 'c']
    }
    superClass.prototype.getSuperVal = function(){
        return this.superVal
    }
    let sup = new superClass()
    //Declare subclass 1
    let subClass = function(){
        this.subVal = false
    }
    subClass.prototype = new superClass()
    subClass.prototype.getSuperVal = function(){
        this.subVal
    }
  }

Class inheritance means declaring two classes, but assigning instances of the first class to the prototype of the second class.

The purpose of the prototype object of a class is to add common methods to the prototype of the class, but the class cannot directly access these properties and methods, it must be accessed through the prototype.When we instantiate a parent class, the newly created object duplicates the constructor and method of the parent class and points the prototype_proto_to the parent's prototype object, thereby having the properties and methods on the parent's prototype object, and this newly created object has direct access to the properties and methods on the parent's prototype object.

let sub = new subClass1()
console.log(sub.superVal)   //true
console.log(sub.getSuperVal)   //false

We can use instanceof to detect whether an object is an instance of a class, and instanceof determines the relationship by determining the prototype chain of the object, regardless of the object and its own structure.

console.log(sub instanceof superClass)    //true
console.log(sub instanceof subClass)    //true
console.log(subClass instanceof superClass)    //false

It is important to note that instanceof is an instance of a subsequent class (object) that determines whether or not the preceding object is an instance of the latter class (object), and does not imply an inheritance relationship between the two.

console.log(subClass.prototype instanceof superClass)    //true

Object is the ancestor of all objects

console.log(sub instanceof Object)    //true

However, Class Inheritance has two drawbacks: (1) Since a subclass inherits its parent through the instantiation of its prototype.So if a common attribute in a parent class references a type, it will be shared by all instances in the subclass, so an instance of a subclass changes the common attribute that the prototype of the subclass inherits from the parent constructor and directly affects other subclasses.

let sub1 = new subClass()
let sub2 = new subClass()
console.log(sub1.books)   //['a', 'b', 'c']
sub2.books.push('d')
console.log(sub1.books)   ////['a', 'b', 'c', 'd']

The modification of sub2 affects the book property of sub1.(2) Since inheritance by subclasses is achieved by prototype instantiation of the parent class, it is not possible to pass parameters to the parent class when it is created, and therefore it is not possible to initialize attributes within the parent constructor when the parent class is instantiated.

Create as Inherit - Constructor Inheritance

let superClass = function(id){
    this.books = ['JavaScript', 'html', 'css']
    this.id = id
}
superClass.prototype.showBooks = function(){
    console.log(this.books)
}
let subClass = function(id){
    superClass.call(this, id)
}
let instance1 = new subClass(10)
let instance2 = new subClass(11)
instance1.books.push('Design Mode')
console.log(instance1.books)  //['JavaScript','html','css','Design Mode']
console.log(instance2.books)  //["JavaScript", "html", "css"]

call is a method that can change the working environment of a function. Calling this method on a superClass is to execute variables in the subclass once in the parent class, which naturally inherits the common properties of the parent class because the parent class binds properties to this.

This type of inheritance does not involve a prototype, so the prototype method of the parent class is not inherited by the child class, and if it is to be inherited by the child class, it must be placed in the constructor so that each instance created will have a separate one and cannot be shared, which violates the principle of code reuse.In order to combine the two modes a little, a combination inheritance was later developed.

Make Advantages for Me - Combinatorial Inheritance
Combinatorial inheritance, as its name implies, combines the two modes of inheritance mentioned above to combine their respective advantages.

let supClass = function(name){
    this.name = name
    this.books = ['JavaScript', 'html', 'css']
}
supClass.prototype.showBooks = function(){
    console.log(this.books)
}
let subClass = function(name, time){
    this.time = time
    supClass.call(this, name)
}
subClass.prototype = new supClass()
let instance1 = new subClass('dzy', 2018) 
let instance2 = new subClass('hxy', 2019) 
console.log(instance1.name, instance1.time)   //dzy 2018
console.log(instance2.name, instance2.time)   //hxy 2019
instance1.books.push('Design Mode')
instance1.showBooks()   //['JavaScript','html','css','Design Mode']
instance2.showBooks()   //["JavaScript", "html", "css"]

Executing a parent constructor in a subclass constructor instantiates the parent on the subclass prototype as a combination pattern, which combines the advantages of class inheritance and constructor inheritance.

Clean Inheritor - Prototype Inheritance

prototype allows you to create a new object from an existing object without creating a new custom object type.
Prototype Inheritance in JavaScript by Douglas Crockford

let inheritObject = function(o){
    //Declare a Transition Function Object
    function F(){}
    //Transition object's prototype inherits parent object
    F.prototype = o
    //Returns an instance of a transition object whose prototype inherits the parent object
    return new F()
}

It is an encapsulation of class inheritance in which the transition object is equivalent to a subclass in class inheritance, but appears as a transition object in the prototype in order to create a new instantiated object to return.

Parasitic Inheritance

let book = {
    name: 'js book',
    alikeBook: ['JavaScript', 'html', 'css']
}
let createBook = function(obj){
    //Create new objects through prototype inheritance
    var o = new inheritObject(obj)
    //Expand New Objects
    o.getName = function(){
        console.log(name)
    }
    return o
}

Parasitic inheritance is the second encapsulation of prototype inheritance and expands the inherited objects in the second encapsulation so that new objects are created not only with attributes and methods in the parent class but also with new attributes and methods.

Ultimate Inheritor-Parasitic Combinatorial Inheritance

Classical inheritance is used in combination with constructor inheritance as mentioned above, but there is a problem that parasitic combinatorial inheritance occurs when the subclass is not an instance of the parent class.

Parasitic inheritance is parasitic and relies on prototype inheritance, which is similar to class inheritance.

let inheritProject = function(subClass, superClass){
    //Copy a prototype copy of the parent class and save it in a variable
    var p = inheritProject(superClass.prototype)
    //Fixed subclass constructor property change secondary because overriding subclass prototype
    p.constructor = subClass
    //Set Subclass Prototype
    subClass.prototype = p
}

In combinatorial inheritance, there is no problem with the properties and methods inherited by constructors, so here we will focus on re-inheriting the prototype of the parent class through parasitic inheritance.What we need to inherit is only the prototype of the parent class, and we no longer need to call the parent class's constructor, in other words, we have already called the parent class's constructor in the constructor inheritance.So what we need is a copy of the parent's prototype object, which we can get through prototype inheritance, but it's problematic to assign it directly to the subclass because the constructor in the replicated object P from the parent's prototype object doesn't point to the subClass subclass object, so it's parasiticIn type inheritance, make a minor enhancement to the duplicate object p, fix its constructor property pointing to an incorrect problem, and assign the resulting duplicate object p to the prototype of the subclass, so that the prototype of the subclass inherits the prototype of the parent class and does not execute the constructor of the parent class.

//Define Parent Class
let supClass = function(name){
    this.name = name
    this.colors = ['red', 'green', 'blue']
}
//Define parent prototype methods
supClass.prototype.getName = function(){
    console.log(this.name)
}
//Define subclasses
let subClass = function(name, time){
    //Constructor Inheritance
    supClass.call(this, name)
    //Subclass New Attributes
    this.time = time
}
//Parasitic Inheritance Parent Prototype
inheritProject(subClass, superClass)
//Subclass New Prototype Method
subClass.prototype.getTime = function(){
    console.log(this.time) 
}
//Create two test methods
let instance1 = new subClass('js book', 2014)
let instance2 = new subClass('css book', 2013)
instance1.colors.push('black')
console.log(instance1.colors)    //['red', 'green', 'blue', 'black']
console.log(instance2.colors)    //['red', 'green', 'blue']
instance2.getName()   //css book
instance2.getTime()   //2013

This inheritance is shown in the following figure:

One of the biggest changes is the handling of subclass prototypes, which are given a reference to the parent prototype, which is an object. One thing to note here is that if a subclass wants to add a prototype method, it must pass through the prototype object, otherwise the object given by the knowledgeable will overwrite the object inherited from the parent prototype.

This content source is summarized in JavaScript Design Patterns

The original text is from my personal blog site: https://www.dzyong.com (Welcome to)

Please note the source of the reprint: Dun Zanyong's personal blog - "JavaScript Design Mode (2) - Implementation and Principles of Multiple Inheritance"

Link address for this article: https://www.dzyong.com/#/View...

Keywords: Javascript Attribute Programming

Added by peppino on Wed, 04 Sep 2019 05:16:34 +0300