Diving into JS inheritance

Diving into JS inheritance

Preface

For flexible js, compared with languages ​​like java, inheritance has many different ways of implementation. The diversity of methods means a large number of knowledge points, which are of course points that cannot be avoided during interviews. Leaving aside ES6 classes, how many traditional inheritance methods do you know? What are the implementation principles of each? Can you talk about the advantages and disadvantages? Here we will look at the development of inheritance using a gradual approach with specific examples.

Prepare

Before talking about js inheritance, let's review how js instantiates objects.

A constructor is a function that can instantiate an object through new. The purpose is to reuse it and avoid manually declaring object instances every time.

The new simple implementation is as follows:

function my_new(func){
    var obj = {}
    obj._proto_ = func.prototype // Modify the prototype chain point and splice it to the func prototype chain func.call(obj) // Instance attribute assignment return obj
}

As can be seen from the above, instance attributes can be assigned to the target object through the constructor call.

It can be inferred that calling the parent class constructor in the subclass can also achieve the purpose of inheritance.

This provides a way of inheriting js, that is, calling through the constructor.

As for the prototype attributes, the sharing of prototype attributes is achieved by modifying the prototype pointer.

The same method can be used for inheritance.

Summarize

Based on the two features of constructor and prototype chain, combined with the flexibility of js language.

Although there are many ways to implement inheritance, they all follow the same principle.

n ways of inheritance

Prototypal inheritance

Definition: This type of inheritance that uses prototypes to create new objects based on existing objects without creating custom types is called prototypal inheritance.

It is clearer to look at the code directly:

function createObj(o) {
  function F() { }
  F.prototype = o;
  return new F();
}
var parent = {
  name: 'trigkit4',
  arr: ['brother', 'sister', 'baba']
};
var child1 = createObj(parent);

On the surface, this method is based on object creation and does not require a constructor (of course, the actual constructor is encapsulated). Only the prototype object is used, so the name is prototype inheritance.

shortcoming:

The more obvious superior

This inheritance cannot be reused, and each subclass instance must go through the complete createObj process.

For subclass objects

Because the constructor is encapsulated in createObj, there is no constructor for it. This results in the inability to pass parameters during initialization.
Supplement: createObj is the Object.create() commonly used in ES6, but Object.create has been improved to allow additional parameters.

Solution:

Since the problem is caused by the lack of a constructor, it is a bold guess that the prototype chain inheritance of the constructor is involved.

Prototype chain inheritance

Definition: In order for a subclass to inherit the properties (including methods) of its parent class, you first need to define a constructor. Then, a new instance of the superclass is assigned to the constructor's prototype.

function Parent() {
  this.name = 'mike';
}
function Child() {
  this.age = 12;
}
Child.prototype = new Parent();
child.prototype.contructor = child // The prototype property is overwritten, so it needs to be corrected.
var child1 = new Child();

That is to directly modify the prototype object of the subclass to point to the instance of the parent constructor, so that the instance attributes and prototype attributes of the parent class are hung on its own prototype chain.

shortcoming

Child.prototype = new Parent() , then the prototype property of the child function itself is overwritten, and if necessary, it must be supplemented later.

When a child object is instantiated, parameters cannot be passed to the parent class constructor.
For example, when new Child() is executed, if you want to overwrite name, you can only do so when Child.prototype = new Parent(). It is a more common requirement to uniformly pass parameters and initialize them when we create new Child().

Solution

How to call the parent class constructor when the subclass is initialized. Combined with the previous foundation, the answer is obvious.

Borrowing constructors (class inheritance)

Class inheritance: calling the supertype constructor inside the subtype constructor.

The ideas are relatively clear and driven by problems.

Since prototype chain subclasses cannot pass parameters to parent classes, wouldn't it be sufficient to call the parent class when the subclass is initialized?

Here is an example:

function Parent(age) {
  this.name = ['mike', 'jack', 'smith'];
  this.age = age;
}
Parent.prototype.run = function () {
  return this.name + ' are both' + this.age;
};
function Child(age) {
  //Call the parent class Parent.call(this, age);
}
var child1 = new Child(21);

This meets the need for parameter transfer during initialization, but the problem is also obvious.

child1.run //undefined

question

Parent class prototype attribute is lost

The parent class initialization only inherits the example properties, and the prototype properties are lost in the prototype chain of the subclass

Solution

The reason for the loss is that the prototype chain does not modify the pointer, so why not just modify the pointer?

Composition inheritance

Definition: Use the prototype chain to implement the inheritance of prototype properties and methods, and use the constructor to implement the inheritance of instance properties.

Example:

function Parent(age) {
  this.name = ['mike', 'jack', 'smith'];
  this.age = age;
}
Parent.prototype.run = function () {
  return this.name + ' are both' + this.age;
};
function Child(age) {
  //Call the parent class constructor Parent.call(this, age);
}
Child.prototype = new Parent(); //Prototype property inheritance Child.prototype.contructor = Child
var child1 = new Child(21);

This problem is avoided:

child1.run() // "mike,jack,smith are both21"

question

Once the functionality is met, it’s time to focus on performance. The problem with this inheritance method is that the parent class constructor is executed twice.

They are:

function Child(age) {
  //Call the parent class constructor, second time Parent.call(this, age);
}
Child.prototype = new Parent(); //Modify the prototype chain pointing to the first time

Solution

The natural solution is to cancel one constructor call. To cancel it, you naturally need to analyze the two executions to see if there is any duplication in functionality.

The first time it also inherits the instance and prototype properties, and the second time it also inherits the instance properties of the parent class.

Therefore, the second time the parent class parameter is not available, so we can only think about whether we can not call the parent class constructor for the first time and only inherit the prototype properties.

The answer is of course yes, the previous prototype inheritance is based on this idea.

Parasitic Combinatorial Inheritance

As the name implies, parasitism refers to encapsulating the method of inheriting prototype properties in a specific method, and combination combines constructor inheritance to supplement the deficiencies of prototype inheritance.

Forgive me, just watch:

function createObj(o) {
  function F() { }
  F.prototype = o;
  return new F();
}
//Inheriting prototype properties, i.e. prototype inheritance function create(parent, child) { 
  var f = createObj(parent.prototype); //Get the prototype object child.prototype = f
  child.prototype.constructor = child; //Enhance the object prototype, that is, keep the original constructor pointing to}

function Parent(name) {
  this.name = name;
  this.arr = ['brother', 'sister', 'parents'];
}
Parent.prototype.run = function () {
  return this.name;
};
function Child(name, age) {
  // Example property Parent.call(this, name);
  this.age = age;
}
// Prototype property inheritance is parasitic in this method create(Parent.prototype,Child);
var child1 = new Child('trigkit4', 21);

In this way, we follow the idea of ​​discovering and solving problems until we reach a relatively complete inheritance method. As for the ES method, this article will not cover it.

Conclusion

Only with a lot of accumulation can you achieve a lot. If you want to get the offer you want, you have to be well prepared and lay a solid foundation. Don't be ambiguous. I understand the principle but my answer is incomplete. This is not much different from not understanding it at all. Set a goal in these not-so-new days to review three knowledge points every week. Believe that if you bloom, butterflies will come to you.

The above is the detailed content of in-depth JS inheritance. For more information about in-depth JS inheritance, please pay attention to other related articles on 123WORDPRESS.COM!

You may also be interested in:
  • Detailed explanation of native Javascript inheritance methods and their advantages and disadvantages
  • Three methods of inheritance in JavaScript
  • Detailed explanation of 6 ways of js inheritance
  • Several ways to implement inheritance in JavaScript
  • Five ways to implement inheritance in js
  • Examples of several inheritance methods in JavaScript
  • Detailed explanation of JavaScript inheritance
  • JavaScript object-oriented class inheritance case explanation

<<:  Problems with installing mysql and mysql.sock under linux

>>:  Detailed explanation of Linux system directories sys, tmp, usr, var!

Recommend

HTML Learning Notes--Detailed Explanation of HTML Syntax (Must Read)

1. What is HTML markup language? HTML is a markup...

An example of using Lvs+Nginx cluster to build a high-concurrency architecture

Table of contents 1. Lvs Introduction 2. Lvs load...

MySQL UNION operator basic knowledge points

MySQL UNION Operator This tutorial introduces the...

How to analyze SQL execution plan in MySQL through EXPLAIN

Preface In MySQL, we can use the EXPLAIN command ...

Vue custom table column implementation process record

Table of contents Preface Rendering setTable comp...

Linux remote login implementation tutorial analysis

Linux is generally used as a server, and the serv...

Using CSS to implement loading animation of Android system

There are two common loading icons on the web, on...

How to solve the problem of FileZilla_Server:425 Can't open data connection

When installing FileZilla Server on the server, t...

Use href in html to pop up a file download dialog box when clicking a link

I learned a new trick today. I didn’t know it befo...

A Deep Dive into the MySQL InnoDB Storage Engine

Preface In MySQL, InnoDB belongs to the storage e...

Better-scroll realizes the effect of linking menu and content

1. Basic use <!DOCTYPE html> <html lang=...

HTML table markup tutorial (9): cell spacing attribute CELLSPACING

A certain distance can be set between cells in a ...

Take you to a thorough understanding of the prototype object in JavaScript

Table of contents 1. What is a prototype? 1.1 Fun...