review
Last article we from the prototype object, constructor, instance of the three attributes and the relationship between the three described the prototype chain, if you are not very clear students can first read the previous article do not say that you do not understand the prototype chain – from the prototype, constructor, instance to understand the prototype chain.
So what is the prototype chain used for? The answer is for inheritance. You can try the following code output on the console
We just input a simple object in his[[protoType]]
There are so many methods on properties that, according to the prototype diagram, we can know that these properties are fromObject
Inherited from the prototype object.
This link o1 -> o1.__proto__(equivalent to object. prototype) inherits.
inheritance
What is inheritance? Each object has a __proto__ attribute that points to the prototype object of its constructor, which also has its own prototype object. From the example, the lines connecting each prototype object are inherited links (this can be well understood from the illustration below).
New process diagram
New process again new and object. Create handwriting process
new Foo
- Create an empty Object f = object.create ()
- Point the empty object’s prototype to the constructor’s prototype (this step is used to inherit the constructor’s prototype)
f.__proto__ = Foo.prototype
- Point this at the empty object and call foo.call (obj)
- Returns the obj
When creating an empty object, redirect the empty object f.protoType to a new prototype (see the green line). This will cause f.protoType. constructor to be lost and need to be specified again. Constructor = F
Prototype chain inheritance
The basic idea of stereotype chain inheritance is to inherit properties and methods of multiple reference types through stereotypes. Review the relationship between constructors, stereotypes, and instances: each constructor has a stereotype object, the stereotype has a property that points back to the constructor, and the instance has an internal pointer to the stereotype. To the code
function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
};
function SubType() {
this.subproperty = false;
}
/ / inherit the SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function () {
return this.subproperty;
};
let instance = new SubType();
console.log(instance.getSuperValue()); // true
Copy the code
Subtype.prototype = new SuperType(); Subtype. prototype is replaced with an instance of SuperType, which means that all properties and methods accessible to a SuperType instance will also exist in subtype. prototype. Subtype. prototype = getSubValue; subType. prototype = getSubValue; subtype. prototype = getSubValue;
From instance, there are two dashed lines __proto__, which is the inheritance chain from which all properties on the instance are inherited. Each property inheritance process is tractable.
disadvantages
- The reference values contained in the stereotype are shared across all instances, which is why attributes are usually defined in constructors rather than stereotypes.
function SuperType() {
this.colors = ["red"."blue"."green"];
}
function SubType() {}
/ / the SuperType \ inheritance
SubType.prototype = new SuperType();
let instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors); // "red,blue,green,black"
let instance2 = new SubType();
console.log(instance2.colors); // "red,blue,green,black"
Copy the code
- When a child type is instantiated, it cannot dynamically pass arguments to all parent types
Borrowing constructor
To solve inheritance problems caused by stereotypes containing reference values. The basic idea is simple: call the superclass constructor in the subclass constructor.
function SuperType() {
this.colors = ["red"."blue"."green"];
}
function SubType() {
SuperType.call(this);
}
let instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors); // "red,blue,green,black"
let instance2 = new SubType();
console.log(instance2.colors); // "red,blue,green"
Copy the code
By using the call()(or apply()) method, the SuperType constructor is executed in the context of a new object created for an instance of SubType. This is equivalent to running all the initialization code in the SuperType() function on the new SubType object. The result is that each instance has its own Colors attribute. The disadvantage subclass also does not have access to methods defined on the parent class stereotype, which simply inherits properties from the parent class constructor
Combination of inheritance
The basic idea is to use stereotype chains to inherit properties and methods on stereotypes and borrow constructors to inherit instance properties.
function SuperType(name){
this.name = name;
this.colors = ["red"."blue"."green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age){ Supertype.call (this, name);
this.age = age;
}
// Inheritance method
SubType.prototype = new SuperType();
SubType.prototype.sayAge = function() { console.log(this.age);
};
let instance1 = new SubType("Nicholas".29); instance1.colors.push("black"); console.log(instance1.colors); // "red,blue,green,black" instance1.sayName(); // "Nicholas"; instance1.sayAge(); / / 29
let instance2 = new SubType("Greg".27); console.log(instance2.colors); // "red,blue,green" instance2.sayName(); // "Greg"; instance2.sayAge(); / / 27
Copy the code
Combinatorial inheritance = stereotype chain inheritance + borrowed constructor inheritance
Combinatorial inheritance can solve the shortcomings of prototype chain inheritance and borrowed constructor inheritance, if not the pursuit of high performance is met in current use.
disadvantages
If you are careful, you can see that the SuperType constructor is executed twice, once when the constructor is borrowed, and once when the prototype chain is inherited. The new SuperType new operator source code helps us to execute a time.
Primary inheritance
The essence of primitive inheritance is to borrow an empty constructor that inherits the stereotype object, and that constructor has a specified stereotype. Does this feel familiar? Yes! That’s the principle behind Object.create, which creates an Object with a specified prototype.
function create(prototype) {
// create an empty function
function F() {};
// 2, specify the null function prototype
F.prototype = prototype;
// instantiate the null function
return new F()
}
let person = {
name: "Nicholas".friends: ["Shelby"."Court"."Van"]};let anotherPerson = create(person);
anotherPerson.name = "Greg";
anotherPerson.friends.push("Rob");
let yetAnotherPerson = create(person);
yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie");
console.log(person.friends); // "Shelby,Court,Van,Rob,Barbie"
Copy the code
disadvantages
Primitive inheritance only inherits the prototype object, not the properties on the constructor.
Parasitic inheritance
Parasitic inheritance is almost the same as primitive inheritance, enhancing the prototype object on the basis of primitive inheritance, and returning the prototype object.
function createAnother(original){
Create a new object by calling the function
let clone = object(original);
clone.sayHi = function() {
// Enhance the object in some way
console.log("hi");
};
// Return this object
return clone;
}
let person = {
name: "Nicholas".friends: ["Shelby"."Court"."Van"]};let anotherPerson = createAnother(person); anotherPerson.sayHi(); // "hi"
Copy the code
Parasitic combinatorial inheritance
In the case of combinatorial inheritance, we know that the disadvantage of combinatorial inheritance is that the parent constructor is executed twice. From above, we learned about parasitic inheritance (an enhanced version of the original type inheritance), combined with the advantages of borrowed constructors.
function inheritPrototype(subType, superType) {
let prototype = object(superType.prototype); // Create an object
prototype.constructor = subType; // Enhance objects
subType.prototype = prototype; // Assign an object
}
function SuperType(name) {
this.name = name;
this.colors = ["red"."blue"."green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
};
function SubType(name, age) {
SuperType.call(this, name);
this.age = age;
}
inheritPrototype(SubType, SuperType);
SubType.prototype.sayAge = function() {
console.log(this.age);
};
Copy the code
subsequent
As I am busy recently, the analysis of ES6 will have to be made up later