preface

Hello, everyone, I am An Buchen, welcome to follow my official account, you can also browse my blog when you have time. This article is often asked in an interview, but it is also difficult to understand the knowledge, so SUMMARIZE what I understand

A brief introduction: Each function has a prototype object. The prototype object has a constructor property that points to the constructor function. When accessing a property or method of the object, the constructor is searched from the object itself. The ultimate goal of a stereotype is for all instances to share their properties and methods (important).

So let’s look at it in code

function People() {};const people = new People();
People.prototype.name = "xiaoxu";// Add stereotype attributes to the constructor
Copy the code

Let’s print a prototype and see what the hell it is

console.log(People.prototype)
Copy the code

We saw that a prototype is an object, yes, it is an object

Given the above brief introduction, the constructor attribute, instance object, and constructor attribute are mentioned, and each function has a prototype. What are these? To understand the prototype chain, you have to understand these things first, so it’s easier to understand them later, so let’s look at them one by one

  • What is a constructor?
  • What’s the difference between a constructor and a normal function?
  • What is an instance object?
  • Constructor?
  • What is a prototype prototype chain?
  • Why is there a prototype chain?
  • The final summary

What is a constructor

The constructor is used to create a new instance object using the new keyword so what does the new process do? This is also an interview question

The execution of the new keyword

  1. Create a new object
  2. The __proto__ implicit stereotype of the instance object points to the stereotype of the People constructor
  3. Let this in the constructor point to our instance object
  4. If the constructor returns an object, it returns that object. If it does not return a value, or if it does not return an object, it returns a new object

Let’s start by creating a constructor

function People() {
  this.name = 'xiaoxu';// Own attributes
  this.age = 28;// Own attributes
  // return {address: 'jx'}; {address: "jiangshangrao "}} {address:" Jiangshangrao "}
  // return 20; If the underlying data type is returned, the data is not returned and a completely new object is created
}
var people = new People();
console.log(people);//{name: "xiaoxu", age: 28}
Copy the code

Look at the return statement commented in the middle of the code above, and look at the fourth clause in the new keyword execution above

What’s the difference between a constructor and a normal function

The difference between the following

  1. The constructor’s this points to the instance itself
  2. A normal function’s this points to the caller
  3. Constructors use the new keyword to create new instance objects; normal functions do not
  4. Constructors are capitalized. Var a = new Object() and var a = new Array() are capitalized

Let’s look at an example:

function People(name, age) {
  this.name = name;
  this.age = age;
  console.log(this);
}
Copy the code

Then execute the constructor and the normal function, and see what each of them prints this

// Execute the constructor
var people = new People('xiaoxu'.28);
// Execute normal functions
People('xiaoxu'.28);
Copy the code

The print result is as follows:

Constructor: if called as a constructor, this points to the current instance object. Normal: this points to the caller, in this case to the window

What is an instance object

  1. The new keyword must be used to create instance objects
  2. The constructor we create using the new keyword, and the object returned by the constructor is the instance object
  3. We can check if the object is an instanceof the constructor by instanceof
function People(name, age) {
  this.name = name;
  this.age = age;
}
var people = new People();

console.log(people instanceof People);//true
Copy the code

People is an instance object of the people constructor

What does constructor mean? What does it do

Prototype object Prototype has a constructor property, which by default points to the constructor of prototype object prototype, but is easily changed. It mainly points to the constructor of the current object, but can also be used to determine the data type and redirect to a constructor

function People() {};var people = new People();
console.log(people);
Copy the code

The print result is as follows:

We see that the constructor in the instance object points to the People constructor

console.log(people.constructor === People);//true points to the People constructor
Copy the code

You can also use constructor to determine data types

var string = new String('This is a string.');
var arr = new Array(1.2.3);
console.log(string.__proto__.constructor === String);//true
console.log(arr.__proto__.constructor === Array);//true
var A = null;
var B = undefined;
console.log('A.__proto__', A.__proto__);//Uncaught TypeError: Cannot read properties of null (reading '__proto__')
console.log('B.__proto__', B.__proto__);//Uncaught TypeError: Cannot read properties of undefined (reading '__proto__')
console.log(A.__proto__.constructor === null);//Uncaught TypeError: Cannot read properties of null (reading '__proto__')
console.log(B.__proto__.constructor === undefined);//Uncaught TypeError: Cannot read properties of undefined (reading '__proto__')
Copy the code

Null and undefined have no implicit __proto__ and therefore no constructor

So how can constructor be changed? Let’s do another example where we define a function

function People() {};Copy the code

Then modify the prototype of the function

People.prototype = {
  name: 'xiaoxu'.handleEvent: function () {
    console.log('This is the event handling method'); }}var people = new People();
console.log(people.constructor);ƒ Object() {[native code]} This is the Object constructor
console.log(people.constructor === People);//false because the constructor points to Object
Copy the code

Note: the constructor property is not written here, but the result of printing is that constructor refers to Object and that people. Constructor === people returns false

So now we specify constructor to point to the constructor

People.prototype = {
  constructor: People,
  name: 'xiaoxu'.handleEvent: function () {
    console.log('This is the event handling method'); }}var people = new People();
console.log(people.constructor);// Prints: People constructor
console.log(people.constructor === People);//true is the constructor pointing to the current object
Copy the code

Constructor then points to the people constructor and returns true for people.constructor === people

So if we change the prototype Object, the constructor inside it must redirect to the Object’s constructor, otherwise it will point to the topmost JS built-in Object constructor

What is a prototype prototype chain

function People() {
  this.name = "xiaoxu"
};
var people = new People();
People.prototype.address = "Shangrao, Jiangxi";
People.prototype.handleEvent = () = > {
  console.log('This is the event handling method');
};
console.log('Instance object', people);

Copy the code

The prototype is an object, and the properties and methods we defined on it are defined on the prototype. If you look at the image above, it starts with its name property. When you expand the prototype chain, you see the Address property and the handleEvent method defined on the prototype

Let’s see if we can get the Address property and the handleEvent method defined on the prototype

console.log(people.address);// Shangrao, Jiangxi province
people.handleEvent();// This is the event handling method
Copy the code

We see in the print results that we do get the properties and methods defined on the prototype. How do we get them?

Let’s take a look at the following code

console.log(people.__proto__.address);// Shangrao, Jiangxi province
people.__proto__.handleEvent();// This is the event handling method
Copy the code

It turns out that it’s also available

Every Object has an implicit prototype, meaning __proto__, which is used to look up properties and methods on the prototype. If it doesn’t have one, it will look up until it finds the top-level Object, whose __proto__ is Null. The process of looking up __proto__ layer by layer is the prototype chain

Let’s look at another example to make it clear

function People() {}; People.prototype.name ="xiaoxu"
var people = new People();
console.log('Constructor prototype', People.prototype);
console.log('Implicit prototype of instance object', people.__proto__);
console.log('Determine if the constructor of the instance object points to a constructor', people.constructor === People);//true
console.log('Determine whether the implicit stereotype of the instance object points to our constructor stereotype', people.__proto__ === People.prototype);//true
// Let's follow the People constructor up
console.log('This is the prototype of the top-level Object.', people.__proto__.__proto__);
// We continue to look up the prototype chain of the Object and print out null
console.log('This is the top-level prototype chain of the Object.', people.__proto__.__proto__.__proto__);//null
Copy the code

Now let’s look at a familiar example

var arr = new Array(1.2.3.4.5.6);  
console.log(arr);  
Copy the code

If you look familiar when you expand the prototype chain, here are the array methods that we’re familiar with, when you’re using array methods, you’re already using the prototype chain to find those methods

There are other built-in constructors, so let’s test them out

var a = new Array(a);/ / array
var f = new Function(a);/ / function
var d = new Date(a);/ / date
var r = new RegExp(a);/ / regular
Copy the code

Let’s use the console.dir method to print out all the properties and methods of the stereotype on the constructor

console.dir(Array.prototype);
console.dir(Function.prototype);
console.dir(Date.prototype);
console.dir(RegExp.prototype);
Copy the code

You can see that the above pictures all have methods defined on the prototype, which are obtained through the prototype chain, and their prototypes encapsulate their methods

Let’s see if we can point to the Object constructor

console.dir(a.__proto__.__proto__.constructor);// Object {}
console.dir(f.__proto__.__proto__.constructor);// Object {}
console.dir(d.__proto__.__proto__.constructor);// Object {}
console.dir(r.__proto__.__proto__.constructor);// Object {}
Copy the code

Printed yes, so let’s keep looking up

console.dir(a.__proto__.__proto__.__proto__);// null
console.dir(f.__proto__.__proto__.__proto__);// null
console.dir(d.__proto__.__proto__.__proto__);// null
console.dir(r.__proto__.__proto__.__proto__);// null
Copy the code

So they both inherit the toString() and valueOf() methods on the top-level Object constructor prototype, which are also defined on the prototype. We can see them by printing Object.prototype

Why is there a prototype chain

Let’s look at another example

function People() {};var people1 = new People();
var people2 = new People();

// We'll start by adding a method to the People1 instance object
people1.handleEvent = () = > {
  console.log('This is the method of the instance object');
}
Copy the code

Then execute the method on the People1 instance object

people1.handleEvent();// This is the method of the instance object
Copy the code

Can execute, no problem

Let’s see if this method exists on our instance object people2

people2.handleEvent();TypeError: People2. HandleEvent is not a function
Copy the code

I want the People2 instance object to have a handleEvent method, too. We can’t write the same method again. If there are too many instances, adding the same method is a waste of resources and would be cumbersome to add

So we can add properties and methods to the prototype and call them through the prototype chain, saving resources

People.prototype.handleEvent = () = > {
  console.log('This is a method added to the prototype that needs to be shared');
};
people1.handleEvent();// This is a shared method added to the prototype
people2.handleEvent();// This is a shared method added to the prototype
Copy the code

And remember, the ultimate goal of the prototype chain is for all instance objects to be able to share their properties and methods

It’s so important that it should be repeated for three times.

Now let’s look at the diagram

The final summary

  1. When an object looks for properties and methods, it looks from itself; if not, it points to the instantiated constructor’s prototype via __proto__
  2. An implicit stereotype is also an object that points to our constructor
  3. All objects except the topmost Object have a __proto_, which is an implicit prototype
  4. The __proto__ implicit prototype is used by an Object to look up properties or methods until it finds the __proto__ property of the topmost Object, which has a value of null. This search is called the prototype chain