table of Contents
inherit
6.3.1 Prototype chain
Prototype chain as the main method of inheritance: the basic idea is to use the prototype to let one reference type inherit the properties and methods of another reference type
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
};
function SubType(){
this.subproperty = false;
}
//inherit from SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
return this.subproperty;
};
var instance = new SubType();
alert(instance.getSuperValue()); //true
alert(instance instanceof Object); //true
alert(instance instanceof SuperType); //true
alert(instance instanceof SubType); //true
alert(Object.prototype.isPrototypeOf(instance)); //true
alert(SuperType.prototype.isPrototypeOf(instance)); //true
alert(SubType.prototype.isPrototypeOf(instance)); //true
The above code defines two constructors: SuperType
and Subtype
, each type has a property and a method, the main difference between them is SubType
inheritance SuperType
.
Inheritance is achieved by creating SuperType
an instance and assigning the instance to the SubType.prototype
realization.
The essence of implementation is to rewrite the prototype object and replace it with an instance of a new type. In other words, SuperType
the properties and methods that originally existed in now also exist in SubType.prototype
.
After establishing the inheritance relationship, we SubType.prototype
added a method, so SuperType
that a new method was added on the basis of the inherited properties and methods.
The end result is this:
instance
Pointed SubType
prototype
SubType
Prototype and directed SuperType
prototype
getSuperValue()
Still in the SuperType.prototype
middle, but property
in the SubType.prototype
middle. This is because it property
is an instance property, but getSuperValue()
a prototype method
-
Note:
instance.constructor
It is now pointing to theSuperType
reason that this is because the originalSubType.prototype
constructor has been rewritten. -
Determine the relationship between prototype and instance:
instanceof
OperatorisPrototypeOf()
method
-
Disadvantages of prototype chain inheritance:
-
All instances of the child constructor will share the definition of the parent constructor
引用类型值属性
.function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ } //inherit from SuperType SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green,black"
Our
instance1.colors
amendments can beinstance2.colors
reflected, which has fully proved this point. -
When creating an instance of a subtype, you cannot pass parameters to the supertype's constructor.
-
6.3.2 Borrowing constructor
In order to solve the problems caused by the inclusion of reference type values in the prototype chain, developers began to use a technique called borrowed constructors.
-
The basic idea: call the supertype constructor inside the subtype constructor (the function is just an object that executes code in a specific environment, so the constructor can also be executed on the newly created object by using the apply() and call() methods.
function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ // inherit from SuperType // here, this will point to instance of SubType SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green"
The background line in the code "seconded" the supertype constructor.
By using the
call()``和apply()
method, we actuallySubType
call theSuperType
constructor in the environment of the newly created instance .In this way, all object initialization codes defined in the function will be
SubType
executed on the new objectSuperType()
,SubType
and all instances of the result will havecolors
copies of their own properties. -
Pass parameters
Compared with the prototype chain inheritance, borrowing the constructor has a big advantage. You can pass parameters to the supertype constructor in the subtype constructor.
function SuperType(name){ this.name = name; } function SubType(){ //inherit from SuperType passing in an argument SuperType.call(this, "Nicholas"); //instance property this.age = 29; } var instance = new SubType(); alert(instance.name); //"Nicholas"; alert(instance.age); //29
-
The problem of borrowing the constructor
If you just borrow the constructor, then you cannot avoid the problem of the constructor mode. The methods are defined in the constructor, so there is no way to talk about function reuse.
The methods defined in the prototype of the supertype are not visible to the subtype.
6.3.3 Combined inheritance
-
Combination inheritance refers to the combination of the prototype chain and the technology of borrowing constructors
-
Idea: Use the prototype chain to implement the inheritance of prototype properties and methods, and use the constructor to implement the inheritance of instance properties.
-
It not only realizes the reuse of functions by defining methods on the prototype, but also ensures that each instance has its own properties.
function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } 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("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27
In this example,
SuperType
two attributes are defined:name
andcolors
.SuperType
The prototype defines a methodsayName()
.SubType
The constructorSuperType
passes inname
parameters when calling the constructor , and then defines its own propertiesage
.Then, assign
SuperType
the instance toSubType
the prototype, and then define the method on the prototypesayAge()
In this way, two different
SubType
instances can both have their own attributes-includingcolors
attributes, and can use the same method. -
Combinatorial inheritance avoids the defects of prototype chain and borrowed constructor inheritance, combines their advantages, and becomes the most commonly used inheritance mode in JavaScript.
-
instanceof
AndisPrototypeOf
be able to recognize objects created based on combined inheritance.
6.3.4 Prototype inheritance
Idea: With the help of prototypes, new objects can be created based on existing objects without having to create custom types.
function object(o) {
function F() {
};
F.prototype = o;
return new F();
}
Inside the object() function, a temporary constructor is created, and then the passed-in object is used as the prototype of the constructor, and finally a new instance of a temporary type is returned. Essentially, object() performs a shallow copy of the object passed in.
function object(o){
function F(){
}
F.prototype = o;
return new F();
}
var person = {
name: "Nicholas",
friends: ["Shelby", "Court", "Van"]
};
var anotherPerson = object(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
var yetAnotherPerson = object(person);
yetAnotherPerson.name = "Linda";
yetAnotherPerson.friends.push("Barbie");
alert(person.friends); //"Shelby,Court,Van,Rob,Barbie"
6.3.5 Parasitic inheritance
-
Parasitic inheritance is an idea closely related to prototype inheritance
-
Idea: Create a function that is only used to encapsulate the inheritance process. The function internally enhances the object in a certain way, and finally returns the object as if it really did all the work.
function createAnother(original) { var clone = object(original) // 通过调用函数创建一个新对象 clone.sayHi = function() { // 以某种方式来增强这个对象 alert("hi") } return clone // 返回这个对象 }
6.3.6 Parasitic combined inheritance
Combinatorial inheritance is the most commonly used inheritance pattern in JavaScript, but it also has its own shortcomings. The biggest problem with combinatorial inheritance is that no matter what the situation is, the supertype constructor will be called twice: once when creating the subclass prototype, and the other time inside the subclass constructor.
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
// 继承属性
SuperType.call(this, name); // 第二次调用SuperType()
this.age = age;
}
// 继承方法
SubType.prototype = new SuperType(); // 第一次调用 SuperType()
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
alert(this.age);
};
When you call the SuperType()
function for the first time , SuperType.prototype
you will get two properties: name
, colors
; They are both SuperType
instance properties, but they are now in SubType
the prototype. When the SubType
constructor is called, the constructor is called again SuperType
, this time creating instance attributes name
and on the new object colors
. Therefore, this attribute blocks the two attributes with the same name in the prototype.
In other words, there are two sets of name and colors attributes: one set in the example and one set in the SubType
prototype. This is SubType
the result of calling the constructor twice .
Fortunately, we have found a way to solve this problem-parasitic combined inheritance.
-
Parasitic combined inheritance: inherit properties by borrowing constructors, and inherit methods through the hybrid form of the prototype chain
-
The basic idea: you don't have to call the supertype's constructor in order to specify the subtype's prototype. All we want is a copy of the supertype's prototype.
-
Essence: Use parasitic inheritance to inherit the prototype of the supertype, and then assign the result to the prototype of the subtype. The basic pattern of parasitic combined inheritance is as follows:
function inheritPrototype(subType, superType) {
var prototype = object(superType.prototype) // 创建对象(超类型原型的一个副本)
prototype.constructor = subType // 增强对象(为创建的副本添加constructor属性)
subType.prototype = prototype // 指定对象
}
function object(o){
function F(){
}
F.prototype = o;
return new F();
}
function inheritPrototype(subType, superType){
var prototype = object(superType.prototype); //create object
prototype.constructor = subType; //augment object
subType.prototype = prototype; //assign object
}
function SuperType(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
alert(this.name);
};
function SubType(name, age){
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function(){
alert(this.age);
};
var instance1 = new SubType("Nicholas", 29);
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
instance1.sayName(); //"Nicholas";
instance1.sayAge(); //29
var instance2 = new SubType("Greg", 27);
alert(instance2.colors); //"red,blue,green"
instance2.sayName(); //"Greg";
instance2.sayAge(); //27
The efficiency of this example is reflected in that it only calls the SuperType
constructor once , and therefore avoids SubType.prototype
creating unnecessary and redundant properties on it. At the same time, the prototype chain can remain unchanged; it can also be used instanceof
andisPrototypeOf()