Several ways in which JavaScript implements inheritance
As a weakly typed object-oriented language, JS inheritance is also one of its very powerful features
Start by defining a parent class
/ / define a Animal function Animal (name) {/ / attribute this. Name = name | | 'Animal'; This.sleep = function(){console.log(this.name + 'sleeping! '); } // animal.prototype. eat = function(food) {console.log(this.name + 'eating:' + food); };Copy the code
Prototype chain inheritance
Core: Use an instance of a parent class as a prototype for a subclass
function Dog(name) {
/ / property
this.name = name || 'Dog';
}
Dog.prototype = new Person();
var dog = new Dog();
console.log(dog.name); // Dog
console.log(dog.eat('bone'));//Dog is eating: bone
console.log(dog.sleep());//Dog is sleeping
console.log(dog instanceof Animal); //true
console.log(dog instanceof Dog); //true
Copy the code
Advantages:
- Very pure inheritance, an instance is an instance of a subclass and an instance of a parent class
- New stereotype methods/attributes in the parent class that are accessible to all subclasses
- Simple and easy to implement
Disadvantages:
- Creating a subclass instance cannot pass arguments to the superclass constructor
- Single inheritance, can not achieve multiple inheritance
- All instances of subclasses share the attributes of their parent instance. All properties of the stereotype object are shared by all instances, and when one instance modifies the stereotype properties, the stereotype properties of the other instances are also changed.
Constructor inheritance
Core: Use.call() and.apply() to enhance the parent class’s constructor, which copies the parent class’s instance properties to the child class (without using the stereotype).
function Cat(name, age){
Animal.call(this, name); // Copy the parent instance attributes to the subclass
this.age = age || 5;
}
var cat = new Cat("Tom".18);
console.log(cat.name); // Tom
console.log(cat.age); / / 18
console.log(cat.sleep()); // Tom is sleeping
console.log(cat.eat("fish")); // Uncaught TypeError: cat.eat is not a function
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
Copy the code
Advantages:
- Inherits only the properties, methods of the parent constructor. There are no attributes and methods inherited from the superclass stereotype.
- The shortcoming of prototype chain inheritance is solved
- Multiple inheritance (that is, you can inherit multiple constructor properties and call multiple constructors in a subclass constructor)
- It is possible to pass arguments to a parent instance from a child instance
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
Combinatorial inheritance (stereotype chain inheritance + constructor inheritance) (common)
Core: Inherits the attributes of the parent class and retains the advantages of passing arguments by calling the parent class constructor, and then implements function reuse by using the parent class instance as a subclass prototype
function Rabbit(name, age) {
Animal.call(this, name); // Constructor inheritance, second call
this.age = age || 5;
}
Rabbit.prototype = new Animal(); // Prototype inheritance is called for the first time
Cat.prototype.constructor = Cat; // The emphasis on composite inheritance also needs to be fixed to the constructor point.
var rabbit = new Rabbit("jine");
console.log(rabbit.name); // jine
console.log(rabbit.age); / / 5
console.log(rabbit.sleep()); // Jine is sleeping
console.log(rabbit.eat("carrot")); // Carrot is eating carrot
console.log(rabbit instanceof Animal); // true
console.log(rabbit instanceof Rabbit); // false
Copy the code
Advantages:
- The constructor defect is remedied. You can inherit instance properties/methods as well as stereotype properties/methods
- Can pass the cords
- Function reuse
- Constructor properties introduced by each subclass instance are private. There is no reference property sharing problem
- Both an instance of a subclass and an instance of a superclass
Disadvantages:
- The parent constructor is called twice, generating two instances (memory loss), and the subclass constructor replaces the parent constructor on the prototype.
Primary inheritance
Core: Wrap an object with a function and return a call to that function. This function becomes an instance or object to which properties and methods can be added at any time. Object.create() works this way. In essence, CreateObject() makes a shallow copy of the object passed into it
function CreateObject(obj) {
var Fun = function() {};
Fun.prototype = obj; // obj.__proto__===Object.prototype true; Fun.prototype.constructor === Object true
return new Fun();
}
var person = {
name: "xiaoming".friend: ["lily"."xiaohong"]}var person1 = CreateObject(person);
var person2 = CreateObject(person);
Person. name does not change after person1.name is changed because person.name is a base type, not a reference type.
person1.name = "xiaohe";
console.log(person2.name); //"xiaoming"
console.log(person.name); //"xiaoming"
// Since person.friend is a reference type, person1.friend changes both the current reference type address and the value of person and person2.
person1.friend.push("xiaozhang");
console.log(person2.friend); // [" Lily ", "xiaohong", "Xiaozhang "]
console.log(person.friend);// [" Lily ", "xiaohong", "Xiaozhang "]
person1.friend = ["xiaowang"]; // Point the friend attribute of Person1 to another reference address.
console.log(person2.friend); // [" Lily ", "xiaohong", "Xiaozhang "]
console.log(person.friend);// [" Lily ", "xiaohong", "Xiaozhang "]
//person1.friend reference refers to a memory address different from person, person2, so person2 and Person friend attributes do not change.
person1.friend.push("xiaoli");
console.log(person1.friend); // ["xiaowang", "xiaoli"]
console.log(person2.friend); // [" Lily ", "xiaohong", "Xiaozhang "]
console.log(person.friend);// [" Lily ", "xiaohong", "Xiaozhang "]
Copy the code
Advantages: Type and a copy of an object, wrapped in a layer of functions
Disadvantages:
- Attributes that contain a reference type value always share the corresponding value
- Reuse cannot be achieved. (New instance attributes are added later)
Parasitic inheritance
Core: is to give the original type inheritance around a shell, you can add properties and methods to the shell
// This constructor has the same effect as object.create ()
function CreateObject(obj) {
var Fun = function() {};
Fun.prototype = obj;
return new Fun();
}
var person = {
name: "xiaoming".friend: ["lily"."xiaohong"]}function CreatChild(obj) {
// Create an Object, or use var newObj = object.create (obj);
var newObj = CreateObject(obj);
newObj.sayName = function() { // Enhance objects
console.log(this.name);
}
return newObj;
}
var child1 = CreatChild(obj);
child1.sayName(); // xiaoming
child1.name="xiaohua";
child1.sayName(); // xiaohua
Copy the code
Advantages: No custom type is created, because only a shell returns an object. Objects can be enhanced. Disadvantages: No prototypes, no reuse of properties and methods.
Parasitic combinatorial inheritance
Core: By parasitic way, the instance attributes of the parent class are cut off, so that when the constructor of the parent class is called twice, the two instance methods/attributes are not initialized, avoiding the disadvantages of combinative inheritance
// Attributes are inherited by borrowing constructors, and methods are inherited by a mashup of prototype chains. Essentially, you use parasitic inheritance to inherit the stereotype of the supertype and then assign the result to the stereotype of the subtype
function Person(name){
this.name = name;
this.colors = ["red"."green"."blue"];
}
Person.prototype.sayName = function(){
console.log(this.name);
};
function Child(name,age){
Person.call(this,name); // Constructor inheritance
this.age = age;
}
(function(){
// Create a copy of the supertype stereotype
var anotherPrototype = Object.create(Person.prototype);
// Reset the default constructor property lost by rewriting the prototype
anotherPrototype.constructor = Child;
// Assign the newly created object to the prototype of the subtypeChild.prototype = anotherPrototype; }) (); Child.prototype.sayAge =function(){
console.log(this.age);
};
var child1 = new Child("luochen".22);
child1.colors.push("purple");
console.log(child1.colors); // "red,green,blue,purple"
child1.sayName();
child1.sayAge();
var child2 = new SubType("tom".34);
console.log(child2.colors); // "red,green,blue"
child2.sayName();
child2.sayAge();
Copy the code
Important: Fixed a problem with composite inheritance.
Examples of inheritance
Core: Adds new features to the parent class instance and returns it as a subclass instance
function Cat(name){ var instance = new Animal(); instance.name = name || 'Tom'; return instance; } var cat = new Cat(); console.log(cat.name); // Tom console.log(cat.sleep()); Console. log(cat instanceof Animal); // Tom is sleeping console.log(cat instanceof Animal); // true console.log(cat instanceof Cat); // falseCopy the code
Disadvantages:
- An instance is an instance of a parent class, not a subclass
- Multiple inheritance is not supported
Copies of the inheritance
Core: Copies the attributes of the parent class in the subclass constructor onto the prototype object of the subclass constructor.
function Cat(name){ var animal = new Animal(); for(var p in animal){ Cat.prototype[p] = animal[p]; } this.name = name || 'Tom'; } var cat = new Cat(); console.log(cat.name); // "Tom" console.log(cat.sleep()); Console. log(cat instanceof Animal); // Tom is sleeping console.log(cat instanceof Animal); // false console.log(cat instanceof Cat); // trueCopy the code
Advantages: Supports multiple inheritance
Disadvantages:
- Low efficiency and high memory footprint (due to copying parent class attributes)
- Unable to get non-enumerable methods of the parent class (non-enumerable methods, not accessible using for in)
ES6 Class syntax sugar inheritance
class Person {
constructor(name) {
this.name = name||"default name";
}
reName(name) {
this.name = name;
}
}
class Child extends Person {
constructor(name) {
super(name);
}
}
var child1 = new Child();
console.log(child1.name); // default name
child1.reName("Tom");
console.log(child1.name); // Tom
Copy the code