preface

As a front-end development engineer, proficient in JS language is a must. No matter in daily work, or go out to interview to find a job, how deep and how good JS master, to a large extent determines how far you can go. Today I will introduce the JS prototype and prototype chain, based on some of my understanding. Because I am also in the learning stage, so if there is any wrong or bad place in the article, please kindly point out.

JS prototype

As we all know, JS complex types are all Object types, and JS is not a fully object-oriented programming language, so how to involve inheritance mechanism, is a problem.

The constructor

Since there is no concept of Class in JS, the designers of JS use constructors to implement inheritance mechanism.

Classes in ES6 can be seen as just syntax sugar. Most of the functions of ES5 can be done. The new class writing method just makes the prototype writing more clear and more like object-oriented programming syntax. This will be explained further below. (From Ruan Yifeng’s Introduction to ES6)

Function Person(name, age) {this.name = name; this.age = age; Const p = new Person('zhangsan', 18);Copy the code

As shown in the above code, the JS constructor generates the instance. However, there is a new problem. The properties or methods assigned by this in the constructor are the instance properties and instance methods of each instance. They cannot share common properties. So a prototype object is designed to store the public properties and methods of the constructor.

Supplementary knowledge: The process by which a constructor creates an instance

  1. Create a new object
  2. Assign the scope of the constructor to the new object (so that this points to the new object)
  3. Execute the code in the constructor (add instance properties and instance methods to the new object)
  4. Return new object

A prototype object

After all this time, it’s time to finally talk about the JS prototype object. When each function is created, it generates a property called prototype. This property refers to an object that is the prototype of the function. The prototype object has a property called Constructor that points to the function. This creates a relationship between the prototype object and its functions.

JS prototype chain

JS prototype object, to introduce the JS prototype chain. Now that we have a constructor, we can use that constructor to create an instance object. At this point, let’s refine our Preson constructor

// Function Preson(name, age) {this.name = name; this.age = age; } // Public method preson.prototype. say = function (word) {console.log(' ${this.name} : ${word} '); } const p1 = new Preson(' 1 ', 18); // Create a Person instance object p1.hasownProperty ('say') // false specifies that p1.say(' Hello world') is not defined on itself; // Call public method print: Zhang SAN says: Hello worldCopy the code

Now, why is p1, the instance object we constructed, able to call methods on the prototype object of the Person constructor? Only properties or methods assigned by this inside the constructor are inherited by the instance. Why is it that the say method defined on the prototype object of the constructor can also be called by the instance? This is where the concept of prototype chains comes in.

_proto_

Each instance object created by the constructor itself has a property __proto__, which refers to the prototype object of the constructor

__proto__ is not a feature of the language itself, it is a private attribute added by various manufacturers. Although it is currently provided in the JS engine of many modern browsers, it is not recommended to use this attribute in production to avoid environment dependence. In a production environment, we can use the object.getPrototypeof method to get the prototype of the instance Object and then add methods/properties to the prototype. (From Ruan Yifeng’s Introduction to ES6)

Now we know that when accessing a property of an object, we first look at the object itself. If not, we look at its implicit __proto__ property, then we look at its constructor’s __proto__. If not, we look at its constructor’s __proto__. This leads to a chain structure called a prototype chain.

Note: Assigning through the p1 instance object’s __proto__ attribute changes the prototype object of its constructor, which is shared by all instances.

// Function Preson(name, age) {this.name = name; this.age = age; } // Public method preson.prototype. say = function (word) {console.log(' ${this.name} : ${word} '); } const p1 = new Preson(' 1 ', 18); // Create a Person instance object const p2 = new Preson(' lee ', 20); // Create a Person instance object const p2 = new Preson(' Lee ', 20); // Create a new Proson instance p1.say('hello world'); // Call public method p1.hasownProperty ('say') // false indicating that p1.__proto__.do = function () {console.log(' add method to stereotype object '); } p2.do(); // Printed out - Adds methods to the prototype objectCopy the code

Therefore, during development, we should be careful not to change the prototype object of the constructor by using the instance object, which will affect other instance objects generated by the constructor.

What does it mean to look up the __proto__ of its constructor? Let’s move on.

Supplementary knowledge: The end of the prototype chain

Since the p1 instance object we constructed earlier has a __proto__ attribute pointing to its constructor’s prototype object, does the constructor’s prototype object have this __proto__ attribute? And if so, to whom does it point? Let’s print it out.

We randomly create A constructor for A, print its prototype property, and see that it has A __proto__ property pointing to an Object in the browser.

When we expand further, we see that the constructor of this Object is function Object, so we know that the __proto__ attribute of all prototype objects refers to the prototype of function Object. The function Object’s prototype does not have a __proto__ attribute; it points to null. We know that the end of the prototype chain is null.

Supplementary knowledge: prototype chain for all objects

Since all complex types of JS are objects, does a function, as an object, also have a prototype chain? Let’s create a constructor in the browser and print its __proto__ attribute to find out:

We can see that its __proto__ attribute refers to a function Object that is the prototype of all functions in JS, and its __proto__ attribute refers to the function Object’s prototype. So that validates the claim that the end of the prototype chain is null.

Finally, I would like to offer a god diagram, wish you understand the JS prototype chain

conclusion

Through the above article, I sort out my understanding of the concept of prototype and prototype chain, and explain the preexistence and present life of each concept in as much detail as possible. Because I am also a front end dish chicken, the purpose of writing this article is not only to let everyone understand the concept of prototype and prototype chain, but also to comb through the knowledge I have mastered. If the above has said wrong or bad place, welcome everyone to put forward valuable advice.

PS: The next post is going to be about some personal understanding of closures.