Home >Web Front-end >JS Tutorial >Six ways to implement inheritance in JavaScript
Description of inheritance in javascript:
Many object-oriented languages support two inheritance methods: interface inheritance and implementation inheritance. Interface inheritance only inherits method signatures, while implementation inheritance inherits the actual methods. In JavaScript, interface inheritance cannot be implemented because the function has no signature, but only implementation inheritance is supported, and implementation inheritance is mainly achieved through the prototype chain.
First of all, quote the official document’s description of the prototype chain: The basic idea is to use prototypes to let one reference type inherit the properties and methods of another reference type. To understand this concept, you must first clarify the relationship between constructors, prototypes, and instances: each constructor (as long as it is a function) has a prototype attribute, which points to an object (this object is the prototype object of the constructor); the prototype object (As long as it is an object), there is a constructor attribute, which points to a constructor; and the instance contains an internal pointer [[Prototype]] pointing to the prototype object. To put it bluntly, the construction of the prototype chain is achieved by assigning an instance of one type to the prototype of another constructor. This way the subtype can access all properties and methods defined on the supertype. Each object has its own prototype object, which uses the prototype object as a template to inherit properties and methods from the prototype object. The prototype object can also have its own prototype and inherit properties and methods from it, layer by layer, and so on. The relationship is called a prototype chain and explains why one object has properties and methods defined on other objects.
Six ways to implement inheritance in javascript:
1. Prototype chain
2. Borrowed constructor
# 3. Combined inheritance (use prototype chain and borrowed constructor in combination )
4, prototype inheritance
1. Prototype chain
PS: SubType inherits SuperType, and inheritance is achieved by creating an instance of SuperType and assigning the instance to the prototype of SubType. The essence of the implementation is to override the prototype object of the subtype and replace it with an instance of the new type. The new prototype object of the subtype has an internal property [[Prototype]] that points to the SuperType prototype, and a property constructor inherited from the SuperType prototype that points to the SuperType constructor. The final prototype chain is like this: instance points to the prototype of SubType, the prototype of SubType points to the prototype of SuperType, and the prototype of SuperType points to the prototype of Object (the default prototype of all functions is an instance of Object, so the default prototype will contain an internal Pointer to Object.prototype). 2. Borrowing constructors (also called fake objects or classic inheritance) PS: By using the apply() or call() method, we are actually creating The SuperType constructor is called in the context of a SubType instance. This causes all object initialization code defined in the SuperType() function to be executed on the new SubType object. As a result, each instance of SubType will have its own copy of the colors property. 3. Combination inheritance (also called pseudo-classical inheritance) PS: Combination inheritance avoids the defects of prototype chain and borrowed constructor, integrates their advantages, and becomes the most commonly used in JavaScript inheritance model. Furthermore, using the instanceof operator and the isPrototype() method can also be used to identify objects created based on compositional inheritance. However, it also has its own shortcomings. The biggest problem is that no matter what the circumstances, the supertype constructor is called twice: once when creating the subtype prototype, and once inside the subtype constructor. 4. Prototypal inheritance PS: Inside the object() function, first create a temporary constructor, and then use the incoming object as the constructor prototype, and finally returns a new instance of this temporary type. Essentially, object() performs a shallow copy of the object passed into it. PS: If you just want one object to be similar to another object, prototypal inheritance is fully capable. But the disadvantage is: properties containing reference type values always share the corresponding value. 5. Parasitic inheritance PS: Parasitic inheritance is also a useful pattern when the main consideration is objects rather than custom types and constructors. The disadvantage of this mode is that it cannot reuse functions. 6. Parasitic combined inheritance PS: The high efficiency of this example is reflected in the fact that it only calls the SuperType constructor once, and thus avoids creating unnecessary objects on SubType.prototype. Required, redundant attributes. At the same time, the prototype chain remains unchanged; therefore, the instance operator and isPrototype() method can be used normally. // 实现原型链的一种基本模式
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
// 继承,用 SuperType 类型的一个实例来重写 SubType 类型的原型对象
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); // true
Disadvantages of the prototype chain:
1. When inheritance is implemented through a prototype, the prototype will actually become an instance of another type. As a result, the original instance attributes naturally become the current prototype attributes, and will be shared by all instances. Understand this way: the instance properties of the reference type value defined in the supertype constructor will become prototype properties on the subtype prototype and be shared by all subtype instances.
2. When creating an instance of a subtype, parameters cannot be passed to the constructor of the supertype. // 在子类型构造函数的内部调用超类型构造函数;使用 apply() 或 call() 方法将父对象的构造函数绑定在子对象上
function SuperType(){
// 定义引用类型值属性
this.colors = ["red","green","blue"];
}
function SubType(){
// 继承 SuperType,在这里还可以给超类型构造函数传参
SuperType.call(this);
}
var instance1 = new SubType();
instance1.colors.push("purple");
alert(instance1.colors); // "red,green,blue,purple"
var instance2 = new SubType();
alert(instance2.colors); // "red,green,blue"
The advantage of borrowing a constructor is that it solves two problems with prototype chain implementation inheritance; the disadvantage of borrowing a constructor is that the methods are all defined in the constructor, so function reuse cannot be achieved. Moreover, methods defined in the supertype's prototype are not visible to subtypes, so all types can only use the constructor pattern. // 将原型链和借用构造函数的技术组合到一块。使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有自己的属性。
function SuperType(name){
this.name = name;
this.colors = ["red","green","blue"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name,age){
// 借用构造函数方式继承属性
SuperType.call(this,name);
this.age = age;
}
// 原型链方式继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
};
var instance1 = new SubType("luochen",22);
instance1.colors.push("purple");
alert(instance1.colors); // "red,green,blue,purple"
instance1.sayName();
instance1.sayAge();
var instance2 = new SubType("tom",34);
alert(instance2.colors); // "red,green,blue"
instance2.sayName();
instance2.sayAge();
// 借助原型可以基于已有的对象创建新对象,同时还不必因此创建自定义类型。
1、自定义一个函数来实现原型式继承
function object(o){
function F(){}
F.prototype = o;
return new F();
}
2. Use the Object.create() method to implement prototypal inheritance. This method accepts two parameters: an object to be used as the prototype of the new object and an object to define additional properties for the new object. This method works the same as the object() method when one parameter is passed in.
When the second parameter is passed in, any properties specified will override the properties of the same name on the prototype object. var person = {
name: "luochen",
colors: ["red","green","blue"]
};
var anotherPerson1 = Object.create(person,{
name: {
value: "tom"
}
});
var anotherPerson2 = Object.create(person,{
name: {
value: "jerry"
}
});
anotherPerson1.colors.push("purple");
alert(anotherPerson1.name); // "tom"
alert(anotherPerson2.name); // "jerry"
alert(anotherPerson1.colors); // "red,green,blue,purple"
alert(anotherPerson2.colors); // "red,green,bule,purple";
// 创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后返回这个对象
function createPerson(original){
var clone = Object.create(original); // 通过 Object.create() 函数创建一个新对象
clone.sayGood = function(){ // 增强这个对象
alert("hello world!!!");
};
return clone; // 返回这个对象
}
// 通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。本质上,就是使用寄生式继承来继承超类型的原型,然后再将结果指定给子类型的原型
function SuperType(name){
this.name = name;
this.colors = ["red","green","blue"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name,age){
SuperType.call(this,name);
this.age = age;
}
// 创建超类型原型的一个副本
var anotherPrototype = Object.create(SuperType.prototype);
// 重设因重写原型而失去的默认的 constructor 属性
anotherPrototype.constructor = SubType;
// 将新创建的对象赋值给子类型的原型
SubType.prototype = anotherPrototype;
SubType.prototype.sayAge = function(){
alert(this.age);
};
var instance1 = new SubType("luochen",22);
instance1.colors.push("purple");
alert(instance1.colors); // "red,green,blue,purple"
instance1.sayName();
instance1.sayAge();
var instance2 = new SubType("tom",34);
alert(instance2.colors); // "red,green,blue"
instance2.sayName();
instance2.sayAge();
The above is the detailed content of Six ways to implement inheritance in JavaScript. For more information, please follow other related articles on the PHP Chinese website!