People who are used to writing TypeScript can easily understand extensions, such as class inheritance and interface inheritance. Portal: www.tslang.cn/docs/handbo... But how did JavaScript implement inheritance before ES2015? There is no doubt that inheritance can only be realized through prototype chain. This article mainly encountered the problem of prototype inheritance when reading. It reviews the following centralized methods of prototype inheritance and arranges them into notes for future reference.
Class inheritance (prototype chain inheritance)
Class inheritance is very simple. To sum up, the prototype of the subclass is given to the instance of the parent class, so as to inherit the properties and methods of the parent class.
// Define the Person class function Person() { this.name = 'zhang san' } // Add member function Person.prototype.getName = function() { console.log(this.name) } // Define the Employee class function Employee() { } // Class inheritance Employee.prototype = new Person() let employee1 = new Employee() console.log(employee1.getName()) // zhang san Copy code
Moreover, you can judge that the subclass instance is the parent class prototype through the instanceof keyword:
let employee1 = new Employee() console.log(employee1 instanceof Employee) // true console.log(employee1 instanceof Person) // true console.log(employee1 instanceof Object) // true, the top-level prototype is Object Copy code
However, there are often many problems with class inheritance:
- The attribute of reference type is shared by all instances;
// Define the Person class function Person() { this.name = 'zhang san' this.skill = ['having dinner', 'sleep'] } // Add member function Person.prototype.getSkill = function() { console.log(this.skill) } // Define the Employee class function Employee() { } // Class inheritance Employee.prototype = new Person() let employee1 = new Employee() employee1.skill.push('Write code') let employee2 = new Employee() employee2.skill.push('Make decisions') console.log(employee1.getSkill()) // ['eat', 'sleep', 'write code', 'make decisions'] console.log(employee2.getSkill()) // ['eat', 'sleep', 'write code', 'make decisions'] Copy code
- When creating an Employee instance, you cannot pass parameters to Person.
Constructor inheritance
Although class inheritance is simple, its disadvantages are very obvious. Can we avoid these disadvantages through other inheritance methods? In fact, constructor inheritance can solve this problem. In summary, constructor inheritance is: the subclass constructor environment executes the parent constructor once.
// Define the Person class function Person() { this.name = 'zhang san' this.skill = ['having dinner', 'sleep'] } // Add member function Person.prototype.getSkill = function() { console.log(this.skill) } // Define the Employee class and inherit the Person class function Employee() { Person.call(this) } let employee1 = new Employee() employee1.skill.push('Write code') let employee2 = new Employee() employee2.skill.push('Make decisions') console.log(employee1.skill) // ['eat', 'sleep', 'write code'] console.log(employee2.skill) // ['eat', 'sleep', 'make decisions'] // Define the Manager class and inherit the Person class function Manager(skills) { Person.call(this, skills) } let manager1 = new Manager(['having dinner', 'sleep', 'Make decisions']) console.log(manager1.skill) // ['eat', 'sleep', 'make decisions'] console.log(manager1.getSkill()) // An error is reported. There is no such method Copy code
It can be seen that constructor inheritance has perfectly solved the two problems of class inheritance, but there is a new problem, that is, constructor inheritance only inherits the properties of the parent class, and the methods in the parent class will not be inherited by the subclasses.
Combinatorial inheritance
At first glance, there are more or less problems with the above two methods, which requires composite inheritance, which is also the most common inheritance method in JavaScript. In a word, class inheritance + constructor inheritance.
// Define the Person class function Person() { this.name = 'zhang san' this.skill = ['having dinner', 'sleep'] } // Add member function Person.prototype.getSkill = function() { console.log(this.skill) } Person.prototype.getName = function() { console.log(this.name) } // Define the Employee class and inherit the Person class function Employee(name, skill) { Person.call(this, name, skill) } Employee.prototype = new Person() let employee1 = new Employee('zhang san', ['having dinner', 'sleep', 'Write code']) console.log(employee1.getName()) // zhang san console.log(employee1.getSkill()) // ['eat', 'sleep', 'write code'] let employee2 = new Employee('li si', ['having dinner', 'sleep', 'Make decisions']) console.log(employee2.getName()) // li si console.log(employee2.getSkill()) // ['eat', 'sleep', 'make decisions'] Copy code
Combined inheritance integrates two inheritance methods, which solves the problems caused by the previous two methods. But in fact, the parent constructor is called twice in one inheritance, which seems very puzzling:
// Set the prototype of the subtype instance and call the parent class constructor Employee.prototype = new Person() // Create a subclass instance and call the parent class constructor Person.call(this, name, skill) Copy code
Prototype inheritance
Someone has proposed a new inheritance method: prototype inheritance. In summary, it is to create a new object according to the existing object without creating a new user-defined object type. In short, prototype inheritance encapsulates the following create function:
function create(o) { function F(){} f.prototype = o return new F() } Copy code
Friends familiar with the ES specification can see that this is the simulated implementation of Object.create(). The disadvantage is still obvious. The value type attribute is copied and the reference type attribute is shared, which is similar to the problem of prototype chain inheritance:
// Define the Person class function Person() { this.name = 'zhang san' this.skill = ['having dinner', 'sleep'] } let person1 = create(Person) let person2 = create(Person) person1.name = 'li si' console.log(person1.name) // li si person1.skill = ['having dinner', 'sleep', 'Write code'] console.log(person2.skill) // ['eat', 'sleep', 'write code'] Copy code
Does this mean that prototype assignment is useless? You can look down.
Parasitic inheritance
The parasitic inheritance method is the same as the name. In summary, it is to create a function that is only used to seal the inheritance process. The function internally enhances the object in some form, and finally returns the object.
function create(o) { let clone = Object.create(o) clone.getName = function() { console.log('get name') } return clone } Copy code
Of course, like constructor inheritance, it does not inherit the parent method. You need to create a method every time you create an object.
Parasitic combinatorial inheritance
Parasitic composite inheritance is actually parasitic inheritance + class inheritance. The purpose is to solve the problem of calling the parent class construction method twice when creating an object by composite inheritance. If you don't use Employee.prototype = new Person(), but indirectly let Employee.prototype access Person.prototype?
function create(o) { function F() {} F. prototype = o return new F () } function prototypr(child, parent) { let prototype = object(parent.prototype) prototype.constructor = child child.prototype = prototype } prototypr(Employee, Person) Copy code
Parasitic combination solves the problem of calling the parent constructor twice, which can be regarded as the ultimate solution of JavaScript.
summary
This paper summarizes class inheritance, constructor inheritance, combinatorial inheritance, prototype inheritance, parasitic inheritance and parasitic combinatorial inheritance. It is recommended that students who do not know much about prototype chain and inheritance take a closer look. For ES6 class inheritance, please move to ES6 introductory tutorial es6.ruanyifeng.com/#docs/class...
reference resources
- JavaScript Design Patterns
- JavaScript advanced programming (Second Edition)