Speaking of prototypes, we have to look at constructors.

The constructor

Constructor () is a function that creates objects of the same format. As follows:

function User(name, age) {
    this.name = name;
    this.age = age;
};
const user1 = new User('Jack'.21);
const user2 = new User('Tom'.18);
Copy the code

Is this more convenient than creating objects with literals? Let’s move on:

function User(name, age) {
    this.name = name;
    this.age = age;
    this.sayHello = function () {
        console.log(I call `The ${this.name}This year,The ${this.age}At the age of `); }};const user1 = new User('Jack'.21);
console.log(user1.sayHello()); // MY name is Jack and I am 21 years old.
const user2 = new User('Tom'.18);
console.log(user2.sayHello()); // MY name is Tom and I am 18 years old.
Copy the code

When creating instance objects that have a common method, storing the sayHello method in different storage Spaces, as in the example above, can be bad for performance, so we need to optimize it:

function User(name, age) {
    this.name = name;
    this.age = age;
};
User.prototype.sayHello = function() {
    console.log(I call `The ${this.name}This year,The ${this.age}At the age of `);
};
const user1 = new User('Jack'.21);
console.log(user1.sayHello()); // MY name is Jack and I am 21 years old.
const user2 = new User('Tom'.18);
console.log(user2.sayHello()); // MY name is Tom and I am 18 years old.
console.log(user1.sayHello === user2.sayHello); // true
Copy the code

In this case, user1 and user2 use the same sayHellow function.

Also, we can’t see sayHello when we print user1 or user2 to view the object, so how can we call it? Which brings us to the archetype, which is our hero today.

Considerations for using constructors:

  1. To make it easier to distinguish a normal function from a constructor, we usually capitalize the first letter of the constructor, i.e., the big hump!
  2. Constructor if notnewThere is no difference between ordinary functions!
  3. When you arenewConstructor, an empty object is generated inside the constructor, andthisIt will automatically point to the empty object, and it will automatically returnthisThe object pointing to. If manualreturnA raw value, the constructor will take thisreturnIgnore, (or returnthisThe object to which it points); If it isreturnA reference value is then treated as a return object and ignoredthisThe object pointing to.

The prototype

Each function object has a prototype. Now let’s see what the prototype looks like. We call it __proto__ :

function User() {};
const user = new User();
console.log(user.__proto__); // {constructor: f};
Copy the code

We can see that the prototype of user is an object. The object has a constructor property, which we call a constructor. Its value is a function.

// Continue with the previous block
console.log(user.__proto__.constructor); // function User() {};
Copy the code

From the output above, we can see that user.__proto__. Constructor points to the user constructor that constructs the user instance object. The reasons are as follows:

[Here’s a picture]

Does that make it clear?

So let’s go back to the previous example, which looks like this:

function User(name, age) {
    this.name = name;
    this.age = age;
}
User.prototype.sayHello = function() {
    console.log(I call `The ${this.name}This year,The ${this.age}At the age of `);
};
const user1 = new User('Jack'.21);
const user2 = new User('Tom'.18);
console.log(user1.__proto__); // {constructor: f};
console.log(user1.__proto__ === User.prototype); // true
console.log(user1.__proto__.constructor === User); // true
// Remember the following code
user1.sayHello(); // MY name is Jack and I am 21 years old.
Copy the code

There is no sayHello method on user1, so how does it find this function and execute it successfully?

This can be all due to __proto__, this great contribution ah, let me briefly introduce.

proto

Each object has an attribute, __proto__, which is used to refer to the protoobject from which it was constructed, as you can see from the example above. It also has a function, let’s look at the following code:

function A() {};
A.prototype.name = 'aaaa';
const a = new A();

function B() {};
B.prototype = a;
const b = new B();
    
function C() {};
C.prototype = b;
const c = new C();
console.log(c.name); // aaaa
Copy the code

We did not add the name attribute to c, why can output?

This is because, when C wants to access the value of name, it looks for itself, and when it doesn’t, it looks for c. prototype along the implicit prototype __proto__ to see if it has it, and if it doesn’t, He will continue along __proto__ to find b. prototype to see if it is present. If it is not, he will continue along __proto__ to find A.prototype and see the name attribute on A.prototype. The value of the name property is returned. If it hasn’t found it yet, it will follow __proto__ to Object. Prototype to see if it has one. If it doesn’t, it will follow __proto__ and return null. Such a chain of __proto__ layers is called a prototype chain.

console.log(Object.prototype.__proto__ === null); // true
Copy the code

Null is the top of the prototype chain!

So sometimes we can use methods that we didn’t create, thanks to the prototype chain!

Ok, that’s all for today’s prototype and prototype chain. Next time I will sort out a more detailed note for you