This is the 23rd day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021
Hello everyone, I am a bowl week, a front end that does not want to be drunk (inrolled). If I am lucky enough to write an article that you like, I am very lucky
Writing in the front
Inheritance is a platitudes in object-oriented. Before ECMAScript6, inheritance in JavaScript was very complicated and there were various kinds of inheritance. Essentially, all inheritance is inseparable from the prototype chain. But the syntax is much simpler.
For the content of the prototype chain, you can refer to the two diagrams in the previous article to understand the prototype chain
This article describes how inheritance was implemented prior to ECMAScript6.
Prototype chain inheritance
By virtue of prototype chain inheritance, the essence is to modify the pointing of the prototype, and the implementation code is as follows:
function ParentClass() {
this.name = 'Bowl Week'
}
ParentClass.prototype.getName = function () {
return this.name
}
// Define subclasses that will inherit from the parent class
function ChildClass() {}
// * Point the prototype of a subclass to an instantiation of the parent class. The subclass has the content of the instantiated parent class
ChildClass.prototype = new ParentClass()
// Instantiate the subclass
var child = new ChildClass()
console.log(child.getName()) / / a bowl of weeks
Copy the code
The code diagram above is as follows:
The red line represents the relationship between the constructor and the instance object’s prototype chain, through which inheritance is implemented.
One drawback of implementing inheritance in this way is that multiple instances will cause the contents of the prototype object to be shared, which will affect each other. The test code is as follows:
function ParentClass() {
this.colors = ['red'.'blue'.'green']}function ChildClass() {}
ChildClass.prototype = new ParentClass()
var child1 = new ChildClass()
var child2 = new ChildClass()
console.log(child1.colors) // [ 'red', 'blue', 'green' ]
child2.colors.push('black')
console.log(child2.colors) // [ 'red', 'blue', 'green', 'black' ]
console.log(child1.colors) // [ 'red', 'blue', 'green', 'black' ]
Copy the code
Child1 in the test code is not modified, but when it is modified, the value in child1 is also changed.
Inheritance by constructor
Inheritance by constructor (also known as fake object or classical inheritance in some sources) is accomplished by using a child object to invoke the parent constructor using the function.call () or function.apply () methods, as shown in the following example:
function Parent() {
// Parent object
this.parent = 'parent'
}
Parent.prototype.name = 'Bowl Week' // Add attributes to the prototype of the Parent object
function Child() {
// Child objects
this.child = 'child'
Parent.call(this) // Use call() or apply() to call the parent constructor for inheritance.
}
const child = new Child()
console.log(child)
console.log(child.name) // undefined // does not inherit the parent class
Copy the code
The execution process is as follows:
The advantage of using this approach is that instances of reference types are not shared by all objects. The disadvantage is that all methods are defined in constructors, so they do not inherit the prototype object, and they are recreated every time an object is instantiated, which takes up memory, not to mention function reuse.
Combinatorial inheritance
The previous two inheritance methods have disadvantages. In the inheritance method based on prototype inheritance, all instantiated objects share the methods and attributes of the prototype, and if there is a change, it will be changed. Constructor inheritance cannot inherit stereotype attributes. Therefore, there is a combination of inheritance, which is based on the prototype inheritance and the inheritance with the help of constructors, to take the essence and discard the dregs.
The basic idea for implementing composite inheritance is as follows
-
Inheritance of attributes and methods of stereotypes is implemented using stereotype chains or primitive inheritance.
-
Inheritance of properties of instance objects is implemented through structure constructors.
In this way, functions can be reused by defining methods on prototypes, while ensuring that each object has its own proprietary attributes.
The sample code looks like this:
// Parent object
function Parent() {
this.parent = 'parent'
}
// Add attributes to the prototype of the Parent object
Parent.prototype.name = 'Bowl Week'
// Child objects
function Child() {
this.child = 'child'
// Use call() or apply() to call the parent constructor for inheritance.
Parent.call(this)}// Solve the problem of prototype objects that do not inherit from constructors
Child.prototype = Parent.prototype
const child = new Child()
console.log(child.name) / / a bowl of weeks
Copy the code
Primary inheritance
We can implement an inheritance using the object.create () method as follows:
var person = {
name: 'Bowl Week'.friends: ['Joe'.'bill'.'Cathy'],}var anotherPerson = Object.create(person)
anotherPerson.name = 'A bowl of sweet'
anotherPerson.friends.push('Daisy')
console.log(person.friends) // [' Zhang SAN ', 'Li Si ',' Wang Wu ', 'Zhao Liu']
Copy the code
The disadvantage of this approach is the same as that of the first one, which is that multiple instances will cause content on the prototype object to be shared, and the content will interact with each other.
Parasitic inheritance
The basis of parasitic inheritance is to enhance the object and return the constructor on the basis of the original type inheritance. Example code is as follows:
var person = {
name: 'Bowl Week'.friends: ['Joe'.'bill'.'Cathy'],}function createAnother(original) {
var clone = Object.create(original) // Create a new object by calling object()
clone.sayMe = function () {
// Enhance objects in some way
}
return clone // Return this object
}
var anotherPerson = createAnother(person)
anotherPerson.sayMe()
Copy the code
Its disadvantages are the same as native inheritance.
Parasitic combinatorial inheritance
This inheritance method is implemented with the help of constructor passing parameters and parasitic inheritance. Example code is as follows:
function inheritPrototype(ChildClass, ParentClass) {
var prototype = Object.create(ParentClass.prototype) // Create object, create a copy of the parent class prototype
// Modify the constructor of the created prototype copy of the parent class and point the prototype of the subclass to this class to form a class that is not associated with the parent class
prototype.constructor = ChildClass
ChildClass.prototype = prototype
}
// The parent class initializes instance properties and stereotype properties
function ParentClass(name) {
this.name = name
this.colors = ['red'.'blue'.'green']
}
ParentClass.prototype.sayName = function () {
console.log(this.name)
}
// Use the constructor to pass enhanced subclass instance attributes (support passing arguments and avoid tampering)
function ChildClass(name, age) {
// Copy all attributes of the parent class
ParentClass.call(this, name)
this.age = age
}
// Point the parent class prototype to the child class
inheritPrototype(ChildClass, ParentClass)
// Add a new subclass stereotype attribute
ChildClass.prototype.sayAge = function () {
console.log(this.age)
}
var instance1 = new ChildClass('Bowl Week'.19)
var instance2 = new ChildClass('A bowl of sweet'.18)
instance1.colors.push('black')
console.log(instance1.colors) // [ 'red', 'blue', 'green', 'black' ]
instance1.sayName() / / a bowl of weeks
instance2.colors.push('yellow')
console.log(instance2.colors) // [ 'red', 'blue', 'green', 'yellow' ]
Copy the code
The efficiency of this example is that it calls the ParentClass constructor only once and thus avoids creating unnecessary, redundant properties on childClass.prototype. At the same time, the prototype chain stays the same; Therefore, instanceof and isPrototypeOf() can also be used normally.
If that doesn’t make sense to you, keep reading. First, let’s extract the core code, as shown below:
Here is the core code, and let’s see what the default ParentClass and ChildClass prototype chains look like:
We then call the inheritPrototype() method and modify the ChildClass prototype.
Finally, don’t forget to copy the parent class’s own properties by calling the parent class with the call() method in the subclass, which is a fairly complete inheritance.
Write in the last
This article introduces six methods of inheritance, in addition to the extends keyword. Although ECMAScript6 adds the class keyword and everything else about classes, the inheritance methods described in this article are not used much anymore.
But ECMAScript6’s new classes are essentially syntactic sugar, and when JavaScript talks about inheritance, the class keyword is always used.
This is the 53rd article in the Learn from Scratch series, Illustrated 6 Ways to Inherit before ES6. If you enjoyed this column, please give me or the column a look
This series of articles in the nuggets first, preparation is not easy to reprint please obtain permission
Phase to recommend
- Summary of 42 front-end layout schemes – Juejin (juejin. Cn)
- JS advanced must be 5 high order functions – nuggets (juejin. Cn)
- – Juejin (juejin. Cn)