preface

Every time we encounter a new concept, we might think of three questions: what is it? Why? What can be solved? This time we will look at the concept of prototype and prototype chain, to solve this 3W (what, why, how), first of all, we have to start from the OBJECT oriented JS…

This article requires a computer, a brain, and a cup of coffeeCopy the code

object-oriented

What is object orientation? I don’t need to say that any programming language has object orientation, and they all have the concept of a class, but not in ECMAScript, except for ES6. Just because ES6 has classes, We can take the concept of prototype and prototype chain, because ES6 is generally optimized on the basis of ES5, and now the interview for a solid foundation of JS requirements are relatively high, the last time I was asked about several inheritance methods, the answer is not completely correct… 🙈

So the question is, how can ES be implemented without the concept of a class? I started with factory mode, but what the hell is this? Continue below 👇

The factory pattern

Just as the literal meaning, take 🌰 for example, the factory needs to make a Doll: first make the Doll’s Object(New Object()), then assign attributes to the Doll, such as color, how high, how heavy, and finally make the Doll, code is as follows:

function createDoll(color,height,weight){ // A function of the manufacturing factory mode
  let o = new Object(a);// Create a doll object
  o.color = color;/ / color
  o.height = height;/ /
  o.weight = weight;/ / multiple
  o.sayColor = function(){// Report the color
    alert(o.color);
  }
  return o;
}
// To show Factory mode, add F(Factory: Factory) to the variable name
let dollF1 = createDoll('orange'.20.10);// To create a doll, call the function above
let dollF2 = createDoll('red'.30.10);/ / same as above
Copy the code

It is possible to make multiple objects by encapsulating all the attributes and methods of an object (so called information about itself) in a factory-mode function

  • Benefits:

    Reduce the amount of duplicate code

  • Disadvantages:

    Unable to identify the type of an object, in other words, which function an object comes from? More on this later, because of this shortcoming, the constructor pattern ~ appears

Constructor pattern

What is a constructor? If a function is called by new, it will be called as a constructor.

function Doll(color,height,weight){// This is a normal function
  this.color = color;
  this.height = height;
  this.weight = weight;
  this.sayColor = function(){
    alert(this.color); }}// To indicate the constructor pattern, add C after the variable name
let dollC1 = new Doll('orange'.20.10);// The function above is called a constructor
let dollC2 = new Doll('red'.30.10);
Copy the code

To better identify constructors, the function name should start with a capital letter, such as capital D above, and then drop the create Object compared to factory mode (let o = new Object();). Directly assign properties and methods to this without the return statement.

What is the advantage of this? The problem that the factory mode cannot recognize the type of the object was mentioned earlier. Let’s first look at the printed result of calling the constructor and calling the factory mode

We should not only read the article, but also type the code so that it is easier to understandCopy the code

Calling the factory pattern results in the following:

Calling the constructor results in the following:

We can see that calling the constructor instead of the factory pattern has a constructor property that points to Doll. To prove that the two are equal, we can print it out:

dollC1.constructor === Doll; //true // What about factory mode dollf1. constructor === createDoll; //false, because the constructor attribute does not find the creteDoll, it cannot be determined from the createDoll function, which is the weakness of the factory patternCopy the code

Why do you have to determine object types? Don’t worry, this is a long list of reasons to explain,

It’s like when you eat delicious food, you have to chew it slowly to know what it tastes like, but when you eat it too fast, you can’t tell what it tastes like, and you can’t explain it to your interviewer or code

The constructor property can be used to identify the Object type, but the constructor property is recommended to use instanceof. This is an instance that can be an Object or a constructor. DollF1__proto__ in factory mode has a constructor under it pointing to Object; Constructor (dollC1__proto__) constructor () {constructor (dollC1__proto__) constructor ();

// Constructor mode
dollC1 instanceof Doll; //true
dollC1 instanceof Object; //true
// Factory mode
dollF1 instanceof createDoll; //false
dollF1 instanceof Object; //false
Copy the code

So this is the advantages and disadvantages of the factory mode and the constructor mode, as to why there is a point to Object, all instances of the Object has an Object constructor, as for details, may be quite long, there is a zhihu big man wrote more interesting, recommend to look at JavaScript world the birth of all things;

But don’t be too naive. Nothing is perfect, and neither is constructors, or I wouldn’t talk about stereotypes and prototype chains. So what’s the downside of constructors? Let’s start with the sayColor method in the constructor, which should be the same on multiple instance objects, but look at the following code at 👇 :

dollC1.sayColor === dollC2.sayColor; //false
Copy the code

It prints false, huh? Why is that? After calls the constructor, can generate multiple instances of different scopes, equivalent to create multiple instances of memory, has its own properties can be understood, but it is not necessary to have their own method, is like saying two people to go on a trip, need to prepare something, due to health problem, bring your own towels (properties), understandable, and then you and friends to take a bath, The more you bring, the heavier you will be. From another point of view, if you don’t bring your own bath lotion and borrow your friend’s bath lotion, can you reduce your capacity? The same goes for constructors. The more properties and methods you have, the more memory you can open up, hence the concept of archetypal patterns (finally here ðŸĪŠ).

Prototype patterns (also called prototypes)

What is a prototype pattern? Prototyping can also be called sharing. Isn’t sharing very popular these days? Shared bikes, shared charging banks, shared cars, etc., a bike can be shared by all, just like a prototype model can be shared by all instances, the difference is that the bike costs money

In prototype mode, we move the properties and methods of the constructor to the prototype object, using prototype:

function Doll(){};
Doll.prototype.color='orange';
Doll.prototype.height=12;
Doll.prototype.weight=6;
Doll.prototype.sayColor=function(){
    console.log(this.color);
}
// To indicate prototype mode, add P after the variable name
let dollP1 = new Doll();
dollP1.sayColor();  //orange;
let dollP2 = new Doll();
Copy the code

This is the prototype mode. The constructor has a disadvantage. The methods of multiple instances are inconsistent.

dollP1.sayColor === dollP2.sayColor; //true
Copy the code

The same, can save a lot of memory, the diagram is as follows:

Then let’s look at dollP1’s print and compare the diagram above:

Doll1.__proto__ (doll.prototype), doll1.__proto__ (doll.prototype), doll1.__proto__ (doll.prototype), doll1.__proto__ (doll.prototype), doll1.__proto__ (doll.prototype), doll1.__proto__ (doll.prototype), doll1.__proto__ (doll.prototype), doll1.__proto__ (doll.prototype), doll1.__proto__ (doll.prototype), doll1.__proto__ (doll.prototype), doll.prototype (doll.prototype) DollP1 will return undefined if it still cannot find dollP1 color and nama:

dollP1.color; //orange
dollP1.name; //undefined
Copy the code

However, if I wanted to add my own attribute to dollP1, such as color, I would add the attribute directly to dollP1, as follows:

dollP1.color='red';
dollP1.color; //red
Copy the code

The diagram is as follows:

Add an attribute to the instance, so that when reading the value of color, it will first search for it in its own instance, and if it finds it, it will return ‘red’, and it will not search for it in the prototype object.

Note: an instance object will return undefined even if it has no assigned value, such as undefined, which means that the instance object will return the value of the property regardless of whether it has been assigned or nullCopy the code

If it looks perfect, let’s try a reference type, such as array, and add an array arr property to the prototype object:

Doll. Prototype. Arr = [1, 2, 3]. // Then modify the array of the prototype object on the instance object dollP1, what happens? dollP1.arr.push(4); //4, returns the length of the array doll.prototype.arr; //[1, 2, 3, 4], well, the arR of the prototype object also changes dollp2.arr; / / [1, 2, 3, 4]Copy the code
Make sure you type code, otherwise you won't be able to experience itCopy the code

For instance objects to modify the prototype object array properties, instance object as a result, the prototype object has been changed, so the prototype objects to lose their principles, want to see if more than one instance object to invoke a prototype object, if you modify the prototype object array properties, multiple instances of objects, all have the same values, that what it means to create multiple instances of object? So this is the disadvantage of the prototype pattern, so there is the composite pattern

Portfolio model

What is the combination pattern? The constructor pattern can create separate instances, while the stereotype pattern can be shared. So put attributes in the constructor pattern and methods in the stereotype pattern, code like this:

function Doll(color,height,weight){
    this.color = color;
    this.height = height;
    this.weight = weight;
    this.arr=[1.2.3];
};
Doll.prototype.sayColor=function(){
    console.log(this.color);
}
let doll1 = new Doll('orange'.14.6);
dollP1.sayColor();  //orange;
let doll2 = new Doll('red'.12.4);

doll1.arr.push(4); / / 4
doll1.arr; / / [1, 2, 3, 4]
doll2.arr; / / [1, 2, 3];
doll1.sayColor === coll2.sayColor; //true
Copy the code

This saves a lot of memory by allowing each instance to have a copy of its properties and share the methods of the prototype object.

Now we have solved the 3W problem of the prototype, and then there is another feature of object-oriented, that is inheritance, and how to solve the problem of inheritance in ES? The answer is the prototype chain, at 👇

Prototype chain

What is a prototype chain? We can break this down into a prototype plus a chain, a prototype, which is the prototype we talked about earlier, and a chain, which is the chain that produces the pointing on the prototype pattern, and we talked about three constructors, the prototype object, the instance object, right? What if you create another constructor and make the prototype of the new constructor equal to the instantiation of the original constructor? How do you understand that? Such as creating a Doll (currently only manufacture Doll, Doll, the default for the Doll), now has a new requirement, to make animal dolls, animal dolls and Doll is similar, can be directly with the aid of Doll, a constructor to instantiate, accused is inherit properties and methods of the Doll, don’t need to create the same attributes, the code is as follows:

function Doll(color,height,weight){ // Default action doll
    this.color = color;
    this.height = height;
    this.weight = weight;
};
Doll.prototype.sayColor=function(){
    console.log(this.color);
}

// The constructor to make the animal doll
function AnimateDoll(name){
    this.name = name;
}
// Instantiate the AnimateDoll prototype object with the Doll constructor
AnimateDoll.prototype = new Doll();
AnimateDoll.prototype.sayName=function(){
    return this.name;
}

let animate1=new AnimateDoll('pig');
animate1.name; //pig
animate1.sayName(); //pig
animate1.color; //undefined because no value is passed
animate1.sayColor(); / / same as above
Copy the code

If want to make new pillow doll, the pillow doll may also be animals, also can be a doll, then use animal dolls constructor instantiates the prototype object, pillow doll can inherit the animal dolls and doll so all properties and methods, the relationship between the three became the prototype chain, of course not only three ~

Inanimate. Color: undefined; inanimate. Color: undefined; inanimate.

function Doll(color,height,weight){
    this.color = color;
    this.height = height;
    this.weight = weight;
};
Doll.prototype.sayColor=function(){
    console.log(this.color);
}

function AnimateDoll(name,... args){
    Doll.call(this. args);// Add a row
    this.name=name;
}

AnimateDoll.prototype = new Doll();
AnimateDoll.prototype.sayName=function(){
    return this.name;
}


let animate1=new AnimateDoll('pig'.'pink'.20.10);
animate1.name; //pig
animate1.sayName(); //pig
animate1.color; //pink
animate1.sayColor(); //pink
animate1.height; / / 20
animate1.weight; / / 10
Copy the code

Inheritance method is not only the prototype chain, there are other, interested, you can go to see the little red book or Google ~

The question “why do we have to judge object types?” was mentioned earlier. Without object types, we would not be able to determine what an object refers to, and therefore would not be able to implement inherited methods.

So far roar ~ feel good, beg a praise ~ feel have insufficient, beg a suggestion ~