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 fromObjectInherited 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