Prototype chain inheritance
Inheritance is achieved by pointing the prototype of a child class to an instance of the parent class. If a parent class has a private property of reference type, then this property is shared by all subclasses when it is inherited as a public property, and any change to the current property by any subclass will affect all other inherited subclasses.
Advantages
- Subclasses can access the prototype methods and properties added by the parent class.
- Simple and easy to use.
Disadvantages
- Subclasses can only inherit from a single parent class, no multiple inheritance is possible.
- The properties of the prototype object are shared by all instances.
- Subclass instances cannot dynamically pass parameters to the parent's constructor.
- New methods of subclasses must be placed after prototype replacement.
Instances
function Person(name, age) {
this.name = name;
this.age = age;
this.children = [1, 2];
this.setName = function() {};
}
Person.prototype.addChild = function() {};
function Student(score) {
this.score = score;
this.setScore = function() {};
}
// The prototype of the child class is used as an instance object of the parent class to achieve the inheritance relationship
Student.prototype = new Person();
// The prototype will be overridden and the newly defined methods need to be placed after the prototype replacement.
Student.prototype.sayName = function() {};
var student1 = new Student(1000);
var student2 = new Student(2500);
student1.children.push(3);
console.log(student1);
console.log(student2);
console.log(student1.children); // [1, 2, 3]
console.log(student2.children); // [1, 2, 3]
console.log(student1.__proto__ === student2.__proto__); // true point to Student
console.log(student1.__proto__. __proto__ === student2.__proto__. __proto__); // true points to Person
Constructor inheritance
The parent constructor is called from within the subtype constructor via call()
.
Advantages
- Solves the problem of subclass instances sharing parent reference properties in prototype chain inheritance.
- Enables a single subclass to inherit from multiple parent classes.
- Subclass instances can dynamically pass parameters to the parent class.
Disadvantages
- Poor function reusability, each subclass creates a copy of the parent instance function, which affects performance.
- Instances are only instances of the child class and not of the parent class.
- Subclasses can only inherit the instance properties and methods of the parent class, and cannot inherit properties and methods on the prototype.
Example
function Person(name, age) {
this.name = name;
this.age = age;
this.children = [1, 2];
this.setName = function() {};
}
Person.prototype.addChild = function() {};
function Student(name, age, score) {
Person.call(this, name, age);
this.score = score;
this.setScore = function() {};
}
var student1 = new Student('Jhon', 26, 1000);
console.log(student1);
console.log(student1.addChild); // undefined
console.log(student1.__proto__); // Student
console.log(student1.__proto__. __proto__); // Object
Combinatorial Inheritance (Prototype Chain + Constructor Combinatorial Inheritance)
Combined inheritance is the inheritance of prototype properties and methods using a prototype chain and instance properties using a constructor.
Disadvantages
- Subtypes cannot dynamically pass parameters to supertypes.
- The supertype constructor will be called twice.
Example
function Parent(username, password) {
this.password = password
this.username = username
}
Parent.prototype = {
login() {
console.log(`login as , ${this.username}, password is ${this.password}. `)
}
}
function Child(username, password) {
Parent.call(this, username, password) // second call
this.articles = 30
}
Child.prototype = new Parent() // first call
// Child.prototype = Object.create(Parent.prototype) // This approach avoids the problems with the current inheritance approach
const user = new Child('jweboy', 'jl0630')
// user.login()
// console.log(user.articles)
Prototype inheritance
Prototype inheritance means creating a temporary constructor, then using the incoming object as a prototype for that constructor, and finally returning a new instance of the temporary type. ECMAScript5
adds the Object.create
method to standardize proto-typing inheritance.
// The following method is also a concrete implementation of Object.create
function object(obj) {
function F() {}
F.prototype = obj;
return new F();
}
Parasitic inheritance
Parasitic inheritance is the creation of a function that is used only to encapsulate the inheritance process, which internally augments the object in some way and finally returns that object.
Disadvantages
- Similar to constructors, functions are hard to reuse.
function createObject(obj) {
const clone = Object.create(obj); // create a new object
clone.run = function() { // some way to enhance the object
return this.name;
};
return clone; // return the object
}
const obj = createObject({ name: 'tao' });
// obj.run(); // 'tao'
// console.dir(obj);
Parasitic Combinatorial Inheritance
Parasitic combinatorial inheritance is inheriting properties through constructors and methods through prototype chains.
Advantages
- Subtypes can pass parameters to supertypes dynamically.
- Constructors of supertypes are executed only once.
- Subtype properties are created in their own prototype chains, and properties are not shared between subtypes.
function inheritPrototype(child, parent) {
// Create a copy of the supertype prototype
const prototype = Object.create(parent.prototype)
// Override the missing constructor property for the created copy
prototype.constructor = child
// the created copy is assigned to the prototype of the subtype
child.prototype = prototype
child.prototype = prototype }
function Parent(username, password) {
this.password = password
this.username = username
}
Parent.prototype.login = function() {
console.log(`login as , ${this.username}, password is ${this.password}. `)
}
function Child(username, password) {
Parent.call(this, username, password) // property inheritance
this.articles = 30
}
// Inheritance
inheritPrototype(Child, Parent)
Child.prototype.read = function() {
console.log('read article at', this.articles)
}
const user = new Child('jweboy', 'jl0630')
// console.dir(user)