Implementation method of JS inheritance and detailed explanation of its advantages and disadvantages
- 2021-08-10 06:35:11
- OfStack
Preface
JS is an object-oriented weakly typed language, and inheritance is one of its most powerful features. So how do you implement inheritance in JS? Let's wait and see.
Implementation of JS Inheritance
Since we want to implement inheritance, we must first have a parent class with the following code:
// Definition 1 Animals
function Animal (name) {
// Attribute
this.name = name || 'Animal';
// Instance method
this.sleep = function(){
console.log(this.name + ' Sleeping! ');
}
}
// Prototype method
Animal.prototype.eat = function(food) {
console.log(this.name + ' Eating: ' + food);
};
1. Prototype chain inheritance
Core: Take the instance of the parent class as the prototype of the subclass
function Cat(){
}
Cat.prototype = new Animal();
Cat.prototype.name = 'cat';
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.eat('fish'));
console.log(cat.sleep());
console.log(cat instanceof Animal); //true
console.log(cat instanceof Cat); //true
Features:
Very pure inheritance relationship, the instance is an instance of a subclass and an instance of a parent class A new prototype method/prototype attribute is added to the parent class, which can be accessed by all subclasses Simple and easy to implementDisadvantages:
To add properties and methods to a subclass, it must be executed after a statement like new Animal () and cannot be placed in the constructor
Unable to implement multiple inheritance
All attributes from the prototype object are shared by all instances (reference attributes from the prototype object are shared by all instances) (see Appendix Code: Example 1 for details)
Cannot pass parameters to parent class constructor when creating subclass instance
Recommended index: ★ ★ (3 and 4 fatal defects)
2017-8-17 10:21:43 Added: Thanks to MMHS for pointing out. Wrong description in Disadvantage 1: You can add instance attributes to the Cat instance in the Cat constructor. If you want to add prototype properties and methods, they must be executed after statements like new Animal ().
2018-9-10 00:03:45 Added: Thanks for pointing out IRVING_J. The description in Disadvantage 3 is insufficient. Corrected to: All attributes from prototype objects are shared by all instances.
2. Construct inheritance
Core: Using the constructor of the parent class to enhance the subclass instance is equivalent to copying the instance attribute of the parent class to the subclass (no prototype is used)
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
Features:
It solves the problem that subclass instances share the reference attributes of parent class in 1 When you create a subclass instance, you can pass parameters to the parent class Multiple inheritance can be implemented (call multiple parent class objects)Disadvantages:
An instance is not an instance of a parent class, but an instance of a subclass You can only inherit instance properties and methods of the parent class, not prototype properties/methods Function reuse cannot be realized, and each subclass has a copy of the parent class instance function, which affects performanceRecommended index: ★ ★ (Disadvantage 3)
3. Instance inheritance
Core: Add a new feature to the parent class instance and return it as a subclass instance
function Cat(name){
var instance = new Animal();
instance.name = name || 'Tom';
return instance;
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false
Features:
There is no restriction on how to call, whether it is an new subclass () or a subclass (), the returned object has the same effect
Disadvantages:
An instance is an instance of a parent class, not a subclass Multiple inheritance is not supportedRecommended index: ★ ★
4. Copy inheritance
function Cat(name){
var animal = new Animal();
for(var p in animal){
Cat.prototype[p] = animal[p];
}
Cat.prototype.name = name || 'Tom';
}
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
Features:
Support multiple inheritance
Disadvantages:
Low efficiency and high memory consumption (because you want to copy the attributes of the parent class) Unable to get non-enumerable method of parent class (non-enumerable method, not accessible using for in)Recommended index: ★ (Disadvantage 1)
5. Combination inheritance
Core: Inheriting the attributes of the parent class and retaining the advantages of passing parameters by calling the parent class construction, and then realizing function reuse by taking the parent class instance as the subclass prototype
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
Cat.prototype = new Animal();
// Thank you @ There's always something new to study c Combination inheritance also needs to be fixed as pointed by the constructor.
Cat.prototype.constructor = Cat;
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true
Features:
It remedies the defect of Mode 2, and can inherit instance attributes/methods as well as prototype attributes/methods Is an instance of both a subclass and a parent class There is no reference property sharing problem Transmissible parameter Function reusabilityDisadvantages:
The parent constructor is called twice, and two instances are generated (the subclass instance masks the one on the subclass prototype)
Recommended index: ★ ★ ★ (only 1 extra point of memory is consumed)
6. Parasitic combination inheritance
Core: Cut off the instance attribute of the parent class by parasitic way, so that when calling the construction of the parent class twice, the instance method/attribute will not be initialized twice, thus avoiding the disadvantage of combined inheritance
function Cat(name){
Animal.call(this);
this.name = name || 'Tom';
}
(function(){
// Create 1 Classes without instance methods
var Super = function(){};
Super.prototype = Animal.prototype;
// Prototypes with instances as subclasses
Cat.prototype = new Super();
})();
// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true
Thank you @bluedrink Remind that this implementation does not fix constructor .
Cat.prototype.constructor = Cat; // Need to fix the following constructor
Thanks for the @ bluedrink reminder, this implementation does not fix constructor.
Cat. prototype. constructor = Cat; //Need to fix the lower constructor
Features:
Be called perfect
Disadvantages:
The implementation is more complicated
Recommended index: ★ ★ ★ (complicated implementation, deduct 1 star)
Appendix code:
Example 1:
function Animal (name) {
// Attribute
this.name = name || 'Animal';
// Instance method
this.sleep = function(){
console.log(this.name + ' Sleeping! ');
}
// Instance reference property
this.features = [];
}
function Cat(name){
}
Cat.prototype = new Animal();
var tom = new Cat('Tom');
var kissy = new Cat('Kissy');
console.log(tom.name); // "Animal"
console.log(kissy.name); // "Animal"
console.log(tom.features); // []
console.log(kissy.features); // []
tom.name = 'Tom-New Name';
tom.features.push('eat');
// Changes to the parent class instance value type members do not affect
console.log(tom.name); // "Tom-New Name"
console.log(kissy.name); // "Animal"
// Changes that refer to type members for parent class instances will affect other subclass instances by
console.log(tom.features); // ['eat']
console.log(kissy.features); // ['eat']
Cause analysis:
Key point: Attribute lookup process
To execute tom. features. push, first look for the instance property of the tom object (not found),
Then look for it in the prototype object, which is an instance of Animal. If it is found, it will be directly in the object's
features property.
In console. log (kissy. features); When. Same as above, there is no kissy instance, so look for it on the prototype.
If it happens to exist on the prototype, it will be returned directly, but notice that the features attribute value in this prototype object has changed.