MEMEPh. ideas that are worth sharing...

Six common inheritance methods in JavaScript

Foreword


An important aspect of object-oriented programming is the inheritance of objects. By inheriting the B object, the A object can directly possess all the properties and methods of the B object . This is very useful for code reuse.

Most object-oriented programming languages ​​implement object inheritance through "classes". Traditionally, inheritance in the JavaScript language is not achieved through classes (ES6 introduced the class syntax), but through "prototypes". So what are the common inheritance methods in JS?

 

Method 1. Prototype chain inheritance


The key to this approach is that the prototype of the subtype is an instance object of the supertype.

// parent type

function Person(name, age) {
this.name = name,
this.age = age,
this.play = [1, 2, 3]
this.setName = function () {}
} 
Person.prototype.setAge = function () {}

 //Subtype
function Student(price) {
this.price = price
this.setScore = function () {}
} 

Student.prototype = new Person() // The prototype of the subtype is an instance object of the supertype
var s1 = new Student(15000)
var s2 = new Student(14000)
console.log(s1,s2)

But the essence of this approach is to point the prototype of the subclass to the instance of the parent class, so the instance of the subclass can access the Student.prototype, which is the instance of Person, through __proto__, so that the parent class can be accessed. The private method of the parent class can be obtained by __proto__ pointing to the prototype of the parent class . Therefore, the private and public methods and properties of the parent class are treated as public properties of the subclass.

 

The subclass inherits the properties and methods of the parent class by using the private properties and public methods of the parent class as its own public properties and methods . We all know that when operating basic data types, the operation is the value, and when operating the reference data type The operation is the address. If there is an attribute of the reference type in the private attribute of the parent class, it will be used as a public attribute when it is inherited by the subclass, so that when the subclass 1 operates this attribute, it will affect the subclass 2.

s1.play.push(4)
console.log(s1.play, s2.play)
console.log(s1.__proto__ === s2.__proto__)//true
console.log(s1.__proto__.__proto__ === s2.__proto__.__proto__)//true      

The play attribute in s1 changes, and at the same time, the play attribute in s2 also changes.

Another point to note is that when we need to add new methods to subclasses or override methods of parent classes, remember to put them after the statement that replaces the prototype.

 

function Person (name, age) {
this.name = name,
this.age = age
}

Person.prototype.setAge = function () {
console.log("111")
}

function Student (price) {
this.price = price
this.setScore = function () { }
}
// Student.prototype.sayHello = function () { }//It is invalid to write prototype methods and properties of subclasses here,
//Because it will change the pointer of the prototype, it should be placed after re-designation
Student.prototype = new Person()
Student.prototype.sayHello = function () { }
var s1 = new Student(15000)
console.log(s1)

 

Features :

Disadvantages :

 

Method 2: Borrowing Constructor Inheritance


The key to this method is: in the subtype constructor, the general call() calls the supertype constructor

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)

This method only implements partial inheritance. If the prototype of the parent class has methods and properties, the subclass cannot get these methods and properties.

console.log(s1.setAge())//Uncaught TypeError: s1.setAge is not a function

Features :

Disadvantages :

 

Method 3: Prototype chain + borrowed constructor combined inheritance


The key to this method is that: by calling the parent class structure, inheriting the properties of the parent class and retaining the advantages of passing parameters, and then by using the parent class instance as the child class prototype to achieve function reuse.

 

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//Combined inheritance also needs to fix what the constructor points to
Student.prototype.sayHello = function () { }
var s1 = new Student('Tom', 20, 15000)
var s2 = new Student('Jack', 22, 14000)
console.log(s1)
console.log(s1.constructor) //Student
console.log(p1.constructor) //Person

 This method combines the advantages of prototype chain inheritance and constructor functions, and is the most commonly used inheritance pattern in JavaScript. However, there is also the disadvantage that in any case, the constructor will be called twice: once when the subtype prototype is created, and once inside the subtype constructor, the subtype will eventually contain all instances of the supertype object. properties, but we had to override those properties when calling the subclass constructor.

 

Advantages :

Disadvantages :

 

Method 4: Combined Inheritance Optimization 1


In this way, the parent class prototype and the child class prototype point to the same object, and the child class can inherit the public methods of the parent class as its own public methods, and will not initialize the instance methods/properties twice, avoiding the shortcomings of combined inheritance .

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 = Person.prototype
Student.prototype.sayHello = function () { }
var s1 = new Student('Tom', 20, 15000)
console.log(s1)      

But this way there is no way to distinguish whether the object is a subclass or a superclass instantiation

console.log(s1 instanceof Student, s1 instanceof Person)//true true
console.log(s1.constructor)//Person

Advantages :

Disadvantages :

Method 5: Combined inheritance optimization 2

With the help of prototypes, objects can be created based on existing objects, and var B = Object.create(A)the A object is used as the prototype to generate the B object. B inherits all the properties and methods of A.

function Person (name, age) {
  this.name = name,
  this.age = age
}

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 = Object.create(Person.prototype)
Student.prototype.constructor = Student
var s1 = new Student('Tom', 20, 15000)
console.log(s1 instanceof Student, s1 instanceof Person) // true true
console.log(s1.constructor) //Student
console.log(s1)      

Likewise, Student inherits all the properties and methods of the Person prototype object. For now, the most perfect inheritance method!

 

Method 6: Inheritance of classes in ES6


The class keyword was introduced in ES6. Class can implement inheritance through the extends keyword, and can also define static methods of the class through the static keyword. This is much clearer and more convenient than ES5's implementation of inheritance by modifying the prototype chain.

The essence of ES5 inheritance is to first create the instance object this of the subclass, and then add the method of the parent class to this (Parent.apply(this)). The inheritance mechanism of ES6 is completely different. The essence is to first add the properties and methods of the instance object of the parent class to this (so the super method must be called first), and then use the constructor of the subclass to modify this.

It should be noted that the class keyword is just syntactic sugar for prototypes, and JavaScript inheritance is still implemented based on prototypes .

class Person {

//call the constructor of the class
constructor (name, age) {
this.name = name
this.age = age
} 

//define the general method

showName() {
console.log("Call the method of the 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 constructor of the parent class through super
this.salary = salary
} 

showName () {//Define the method in the subclass itself
console.log("Call the subclass's method")
console.log(this.name, this.age, this.salary);
} 
}

let s1 = new Student('wade', 38, 1000000000)
console.log(s1)
s1.showName()

 

Advantages :

Disadvantages :