Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

preface

Presumably, have learned Java and C++ partners, for the inheritance of the word should not be unfamiliar, recently I have also been consolidating the knowledge of JavaScript, today to learn about JavaScript inheritance.

What is inheritance?

First we need to clarify the concept of inheritance:

Inheritance is the ability of one object to access properties and methods in another object

B inherits from A, so B also has the color property that A has. If we touch CSS, there will be style inheritance

The purpose of inheritance?

The purpose of inheritance, I think, is to achieve the design of the parent class, and code reuse.

Way of inheritance

Java, c++, etc. : Java is through the class, c++ is through:

Our JavaScript, on the other hand, is through the prototype chain. ES2015/ES6 introduced the class keyword, but that’s just syntactic sugar. JavaScript inheritance still has nothing to do with class-based inheritance.

Prototype and prototype chain

JavaScript has only one structure: objects.

Each object in JavaScript contains a hidden attribute __proto__. We call the hidden attribute proto the prototype of the object. Proto points to another object in memory, we call the object proto points to the prototype of the object. The object then has direct access to the methods or properties of its prototype object.

We can see that when using C.name and C.color, the attributes name and color give the impression that they are attributes of C itself, but in fact these attributes are located on the prototype object. We call this path to find attributes the prototype chain

Each instance object has a private property (called proto) that points to its constructor’s prototype. The prototype object also has a prototype object of its own (PROTO), cascading up until an object’s prototype object is null. Null, by definition, has no prototype and serves as the last link in the prototype chain.

Check to null, proof chain end ~

To summarize: Inheritance is the ability of one object to access properties and methods in another object. In JavaScript, we implement inheritance through stereotypes and stereotype chains.

Way of inheritance

How does a constructor create an object

If I have a little Java foundation, I will see if this piece will be particularly exciting. I came into contact with this concept after learning Java and understood it smoothly.

function DogFactory(type, color) {
    this.type = type;
    this.color = color
}

var dog = new DogFactory('Dog'.'Black')
Copy the code

The process of creating an instance

var dog = {};
dog.__proto__ = DogFactory.prototype;
DogFactory.call(dog,'Dog'.'Black');
Copy the code

Looking at this figure, we can see that the execution process is divided into three steps:

  • First, a blank object dog is created;

  • Then, the DogFactory prototype property is set to the dog prototype object, which is a key step in setting the dog prototype object.

  • Finally, use dog to call DogFactory. At this time, this in DogFactory function refers to the object dog. Then, use this to perform attribute filling operation on the object dog in DogFactory function, and finally create the object dog.

Every function object has a public prototype property. When you use this function as a constructor to create a new object, the prototype object points to the function’s Prototype property. So any instance created through the constructor can find the properties on the constructor’s Prototype through the prototype chain

Instance proto property == constructor proyoType

Dog.__proto == DogFactory. Prototype

Prototype chain inheritance

How it works: The essence of an implementation is to point the prototype of a subclass to an instance of its parent class

Advantages:

  • New stereotype methods/attributes in the parent class that are accessible to all subclasses
  • Simple and easy to implement

Disadvantages:

  • Multiple inheritance cannot be implemented
  • All properties from the stereotype object are shared by all instances
  • Cannot pass arguments to the parent constructor when creating a subclass instance

/ / parent types
function Person(name, age) {
    this.name = name,
    this.age = age,
    this.play = [1.2.3]
    this.setName = function () { }
}
Person.prototype.setAge = function () {}/ / subtypes
function Student(price) {
    this.price = price
    this.setScore = function () { }
}
Student.prototype = new Person('wang'.23) // The prototype of a subtype is an instance object of the parent type
var s1 = new Student(15000)
var s2 = new Student(14000)
console.log(s1,s2)
Copy the code

Borrow constructors for inheritance

How it works: The generic call() in the subtype constructor calls the parent type constructor

Features:

  • The problem that subclass instances share parent reference attributes in prototype chain inheritance is solved
  • 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 attributes and methods of the parent class can be inherited, not stereotype attributes and methods of the parent class
  • Function reuse is not possible, each subclass has a copy of the parent class instance function, affecting performance
function Person(name, age) {
    this.name = name,
    this.age = age,
    this.setName = function () {}
  }
  Person.prototype.setAge = function () {}
  function Student(name, age, price) {
    Person.call(this, name, age) 
    // Equivalent to:
    /* this.Person(name, age) this.name = name this.age = age*/
    this.price = price
  }
  var s1 = new Student('Tom'.20.15000)
Copy the code

Combinatorial inheritance of prototype chain + borrowing constructor

Principle: By calling the superclass constructor, inherit the attributes of the parent class and retain the advantages of passing parameters, and then reuse functions by using the instance of the parent class as the prototype of the subclass.

Advantages:

  • You can inherit instance properties/methods as well as stereotype properties/methods
  • There is no reference property sharing problem
  • Can pass the cords
  • Functions on superclass prototypes are reusable

Disadvantages:

  • The parent constructor is called twice, generating two instances
function Person(name, age) {
    this.name = name,
    this.age = age,
    this.setAge = function () { }
}
Person.prototype.setAge = function () {
    console.log("111")}function Student(name, age, price) {
    Person.call(this,name,age)
    this.price = price
    this.setScore = function () { }
}
Student.prototype = new Person()
Student.prototype.constructor = Student// Composite inheritance also needs to be fixed to the constructor point
var s1 = new Student('Tom'.20.15000)
var s2 = new Student('Jack'.22.14000)
console.log(s1)
console.log(s1.constructor) //Student
Copy the code

ES6 class inheritance

How it works: ES6 introduces the class keyword. Class extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends extends

When I first saw it, I thought it was Java

Actually, I think class is much more exciting

Advantages:

  • The syntax is simple and easy to understand

Disadvantages:

  • Not all browsers support the class keyword
class Person {
    // Call the class constructor
    constructor(name, age) {
        this.name = name
        this.age = age
    }
    // Define general methods
    showName() {
        console.log("Call method of parent class")
        console.log(this.name, this.age); }}let p1 = new  Person('kobe'.39)
console.log(p1)
// Define a subclass
class Student extends Person {
    constructor(name, age, salary) {
        super(name, age)// Call the parent constructor with super
        this.salary = salary
    }
    showName() {// Define methods in the subclass itself
        console.log("Calling a subclass's method")
        console.log(this.name, this.age, this.salary); }}let s1 = new Student('wade'.38.1000000000)
console.log(s1)
s1.showName()
Copy the code

The last

In fact, I have not used inheritance in the usual project, so I do not understand the specific application scenario, I hope you can give me some advice.

Point a favor, study progress with me bar