The introduction
27 JS series are tentatively planned, from basic, to prototype, to asynchronous, to design mode, to architecture mode, etc.
This is the third article in the JS series, which focuses on JS inheritance, including prototype chain inheritance, constructor inheritance, combinatorial inheritance, parasitic combinatorial inheritance, primitive inheritance, ES6 inheritance, as well as multiple inheritance and new.
ES5 inheritance
Let’s define a parent class
function SuperType () {
/ / property
this.name = 'SuperType';
}
// Prototype method
SuperType.prototype.sayName = function() {
return this.name;
};
Copy the code
First, prototype chain inheritance
The basic idea
Use an instance of a parent class as a prototype for a subclass
/ / parent class
function SuperType () {
this.name = 'SuperType'; // Superclass attributes
}
SuperType.prototype.sayName = function () { // Parent prototype method
return this.name;
};
/ / subclass
function SubType () {
this.subName = "SubType"; // Subclass attributes
};
SubType.prototype = new SuperType(); // Rewrite the prototype object with an instance of a new type
When you instantiate a SuperType here, you actually perform two steps
// 1, the newly created object copies all the attributes and methods in the parent constructor
// 2, and __proto__ points to the parent's prototype object
SubType.prototype.saySubName = function () { // Subclass the prototype method
return this.subName;
}
// Subclass instance
let instance = new SubType();
// instanceof determines if an object is an instanceof a class by judging its prototype chain
instance instanceof SubType; // true
instance instanceof SuperType; // true
/ / note
SubType instanceof SuperType; // false
SubType.prototype instanceof SuperType ; // true
Copy the code
Features:
Using stereotypes, one reference type inherits the properties and methods of another
Advantages:
Inheriting the template of the parent class, and inheriting the prototype object of the parent class
Disadvantages:
-
You can add instance attributes to a subclass instance in the subclass constructor. Prototype = new SuperType(‘SubType’); Such a statement is then executed.
-
Multiple inheritance cannot be implemented
-
All properties from the stereotype object are shared by all instances
/ / parent class function SuperType () { this.colors = ["red"."blue"."green"]; this.name = "SuperType"; } / / subclass function SubType () {} // Prototype chain inheritance SubType.prototype = new SuperType(); 1 / / instance var instance1 = new SubType(); instance1.colors.push("blcak"); instance1.name = "change-super-type-name"; console.log(instance1.colors); // ["red", "blue", "green", "blcak"] console.log(instance1.name); // change-super-type-name 2 / / instance var instance2 = new SubType(); console.log(instance2.colors); // ["red", "blue", "green", "blcak"] console.log(instance2.name); // SuperType Copy the code
Note: When you change the SuperType reference type attribute, this update is shared by all instances of SubType. Underlying type attribute updates do not.
-
When creating a subclass instance, there is no way to pass parameters to the superclass constructor, or to pass parameters to the superclass constructor without affecting all object instances
Second, structural inheritance
Basic idea:
The parent type constructor is called inside the constructor of the child type.
Note:
-
Functions are simply objects that execute code in a particular environment, so apply/ Call is used here.
-
Using the constructor of the parent class to enhance the instance of the child class is equivalent to copying the instance properties of the parent class to the child class (without using the stereotype).
/ / parent class
function SuperType (name) {
this.name = name; // Superclass attributes
}
SuperType.prototype.sayName = function () { // Parent prototype method
return this.name;
};
/ / subclass
function SubType () {
// Call the SuperType constructor
SuperType.call(this.'SuperType'); // In the subclass constructor, pass arguments to the superclass constructor
// To ensure that the parent constructor does not overwrite the attributes of the child class, we need to define the attributes of the child class after calling the parent constructor
this.subName = "SubType"; // Subclass attributes
};
// Subclass instance
let instance = new SubType(); // Run the subclass constructor and run the superclass constructor in the subclass constructor. This is bound to the subclass
Copy the code
Advantages:
Solve the problem of subclass instance sharing parent class reference object in 1, realize multiple inheritance, when creating subclass instance, can pass parameters to the parent class
Disadvantages:
- An instance is not an instance of a parent class, only an instance of a subclass
- Only instance properties and methods of the parent class can be inherited, not stereotype properties/methods
- Function reuse is not possible, each subclass has a copy of the parent class instance function, affecting performance
3. Combinatorial inheritance
As the name implies, composite inheritance is an inheritance pattern that combines prototype chain inheritance and constructor inheritance to give full play to the advantages of both.
Basic idea:
Using stereotype chain inheritance Using inheritance of stereotype properties and methods through constructor inheritance to achieve inheritance of instance properties. This enables function reuse by defining methods on prototypes, while ensuring that each instance has its own attributes.
By calling the superclass constructor, the attributes of the parent class are inherited and the advantages of passing arguments are retained. Then, functions can be reused by using the instance of the parent class as the prototype of the subclass
/ / parent class
function SuperType (name) {
this.colors = ["red"."blue"."green"];
this.name = name; // Superclass attributes
}
SuperType.prototype.sayName = function () { // Parent prototype method
return this.name;
};
/ / subclass
function SubType (name, subName) {
// Call the SuperType constructor
SuperType.call(this, name); // ---- calls SuperType---- for the second time
this.subName = subName;
};
// ---- The first call to SuperType----
SubType.prototype = new SuperType(); // Rewrite the prototype object with an instance of a new type
SubType.prototype.constructor = SubType; // Composite inheritance needs to fix constructor pointing
SubType.prototype.saySubName = function () { // Subclass the prototype method
return this.subName;
}
// Subclass instance
let instance = new SubType('An'.'sisterAn')
instance.colors.push('black')
console.log(instance.colors) // ["red", "blue", "green", "black"]
instance.sayName() // An
instance.saySubName() // sisterAn
let instance1 = new SubType('An1'.'sisterAn1')
console.log(instance1.colors) // ["red", "blue", "green"]
instance1.sayName() // An1
instance1.saySubName() // sisterAn1
Copy the code
The first time the SuperType constructor is called, subtype. prototype gets two attributes name and colors; When the SubType constructor is called, the SuperType constructor is called a second time, this time creating name and colors on the new object properties, which mask the properties of the same name on the prototype object.
// The prototype chain of instanceof: instance is checked against supertype.prototype
instance instanceof SuperType // true
instance instanceof SubType // true
// isPrototypeOf: instance prototype chains are checked against the SuperType itself
SuperType.prototype.isPrototypeOf(instance) // true
SubType.prototype.isPrototypeOf(instance) // true
Copy the code
Advantages:
It makes up for the defect of mode 2. It can inherit instance attribute/method and prototype attribute/method. There is no reference attribute sharing problem, and it can be passed and reused
Disadvantages:
- The parent constructor is called twice, generating two instances (the subclass instance hides the subclass prototype)
Parasitic combinatorial inheritance
In composite inheritance, when the parent constructor is called twice, the instance attributes of the parent are cut off by parasitism, so that the two-instance methods/attributes are not initialized when the two-instance constructor is called, avoiding the disadvantages of composite inheritance
Main ideas:
Attributes are inherited by borrowing constructors, and methods are inherited through a hybrid form of stereotype chains
/ / parent class
function SuperType (name) {
this.colors = ["red"."blue"."green"];
this.name = name; // Superclass attributes
}
SuperType.prototype.sayName = function () { // Parent prototype method
return this.name;
};
/ / subclass
function SubType (name, subName) {
// Call the SuperType constructor
SuperType.call(this, name); // ---- calls SuperType a second time, inheriting the instance attribute ----
this.subName = subName;
};
// ---- The first call to SuperType inherits the stereotype attribute ----
SubType.prototype = Object.create(SuperType.prototype)
SubType.prototype.constructor = SubType; // Note: enhance objects
let instance = new SubType('An'.'sisterAn')
Copy the code
Advantages:
- Only called once
SuperType
Constructor that creates only one copy of the parent class attributes - The prototype chain remains the same
- Can be used normally
instanceof
δΈisPrototypeOf
5. Original type inheritance
Implementation idea:
The idea is to set the stereotype of a subclass to the stereotype of its parent class
/ / parent class
function SuperType (name) {
this.colors = ["red"."blue"."green"];
this.name = name; // Superclass attributes
}
SuperType.prototype.sayName = function () { // Parent prototype method
return this.name;
};
/** step 1 */
// Subclasses inherit instance properties and methods from the parent class through call
function SubType (name, subName) {
SuperType.call(this, name); // Call the SuperType constructor and pass it a parameter
this.subName = subName;
}
/** step 2 */
// Solve the problem that call cannot inherit attributes/methods from its parent class
The object.create method takes an Object as the prototype of the newly created Object, creating an Object with the specified prototype and several specified properties
// Any property specified by this method overrides the property of the same name on the prototype object
SubType.prototype = Object.create(SuperType.prototype, {
constructor: { / / note that specified SubType. Prototype. Constructor = SubType
value: SubType,
enumerable: false.writable: true.configurable: true
},
run : {
value: function(){ // override
SuperType.prototype.run.apply(this.arguments);
// call super
// ...
},
enumerable: true.configurable: true.writable: true}})/** step 3 */
/ / the last: solve SubType. Prototype. Constructor = = = SuperType
// In this case, as specified in the previous step, no further operation is required
// SubType.prototype.constructor = SubType;
var instance = new SubType('An'.'sistenAn')
Copy the code
Multiple inheritance
If you want more inheritance, you can use mixin
/ / parent SuperType
function SuperType () {}
/ / OtherSuperType parent
function OtherSuperType () {}
// Multiple inherited subclasses
function AnotherType () {
SuperType.call(this) // Inherits SuperType instance properties and methods
OtherSuperType.call(this) // Inherit the instance properties and methods of OtherSuperType
}
// Inherit a class
AnotherType.prototype = Object.create(SuperType.prototype);
// Use object. assign to mix others
Object.assign(AnotherType.prototype, OtherSuperType.prototype);
// Object.assign copies functions from the OtherSuperType prototype to the AnotherType prototype, so that all instances of AnotherType can use the OtherSuperType method
// re-specify constructor
AnotherType.prototype.constructor = AnotherType;
AnotherType.prototype.myMethod = function() {
// do a thing
};
let instance = new AnotherType()
Copy the code
The most important part is:
SuperType.call
Inherit instance property methods- with
Object.create()
To inherit stereotype properties and methods - Modify the
SubType.prototype.constructor
The point to
ES6 inheritance
First, implement a simple ES6 inheritance:
class People {
constructor(name) {
this.name = name
}
run() { }
}
Extends is equivalent to the inheritance of a method
// Replace the above three lines of code
class Man extends People {
constructor(name) {
// super is equivalent to inheritance of attributes
// Replace people.call (this, name)
super(name)
this.gender = 'male'
}
fight() { }
}
Copy the code
The core code
The core code of extends inheritance is as follows and is implemented in the same way as the parasitic combinational inheritance described above
function _inherits(subType, superType) {
Create Creates a copy of the parent class prototype
// Enhance the object to compensate for the loss of the default constructor property by rewriting the prototype
// Assign the newly created object to the subclass's prototype subtype.prototype
subType.prototype = Object.create(superType && superType.prototype, {
constructor: { / / rewrite constructor
value: subType,
enumerable: false.writable: true.configurable: true}});if (superType) {
Object.setPrototypeOf
? Object.setPrototypeOf(subType, superType) : subType.__proto__ = superType; }}Copy the code
Usage scenarios for inheritance
- Don’t use them just for the sake of use, it’s just a waste of time.
- When you need to create a series of objects with similar features, create a common object that contains all the common features, and then inherit those features in a more specialized object type.
- Multiple inheritance and confusion should be avoided.
Note: Given the way JavaScript works, the sharing of functionality between different objects is often referred to as delegation-a particular object delegates functionality to a common object type because of features such as prototype chains. This is probably better than calling it inheritance, because the “inherited” functionality is not copied into the “inherited” object, but still exists in the common object.
series
- JS series 1: var, let, const, deconstruct, expand, new, this, class, function
- JS series 2: Constructor, Prototype,proto, [[Prototype]] and Prototype chain
- JS series 3: Six implementations of inheritance
- JS series 4: An in-depth look at the Instanceof operator
For more on this series,Click on the Github homepage
Walking in the final
1. β€οΈ Have fun, keep learning, and always keep coding. π¨ π»
2. If you have any questions or more unique insights, please feel free to comment or contact Me directly (123)! π π
3. π Welcome to pay attention to: front-end bottle Jun, daily update! π