Introduction to the

I came out again to talk to you, the last article we talked about the origin of the prototype, this time we will come to in-depth understanding of the prototype. Without further ado, let’s do it!

This article is not very friendly to beginners, so it is recommended to read the basics.

Ps: What follows is based on the default, not some individual cases.

The prototype

A little bit of a review of what a prototype is, as we said earlier when we talked about the origin of a prototype, a prototype is a common object that allows all the same instances to share properties and methods, and its purpose is to make it easy to use and to save space. But how to make it easy for us to use? Let’s start with a piece of code:

let arr = []; let obj = {}; console.log(arr.push); ƒ Push () {[native code]} console.log(arr.a); //undefined console.log(obj.push); //undefined console.log(obj.toString); // toString() { [native code] }Copy the code

Question: different instances have different attributes. Where do these attributes exist? With that in mind, let’s start with a few attributes that may help us out.

The prototype property

We did not add these properties to array instances and object instances. The prototype is a common object that allows all instances to share properties and methods. This means that these properties must be stored in their specific prototype. ** This is prototype, and by default it refers to the prototype object of the current function.Then combine it with a wave of code:

Function Person() {} let Person = new Person(); // Check whose prototype attribute console.log(person.prototype) is; //undefined console.log(Person.prototype); / / {constructor: ƒ} the console log (Person) prototype. The prototype); //undefined // declare a variable pointing to the address of the array let arr = [1,2,3]; // Check whose prototype attribute console.log(arr.prototype) is; //undefined console.log(Array.prototype); / / [constructor: ƒ, concat: ƒ, copyWithin: ƒ, the fill: ƒ, find: ƒ,...  console.log(Array.prototype.prototype); //undefined //Array is the object type console.log(typeof array.prototype); //object //Array has push property console.log(array.prototype.push); // Array.prototype.push === arr.push; // Array.prototype.push === arr.push; // Array.prototype.push === arr.push; // Array.prototype.push === arr.push; //trueCopy the code

1. Only functions have prototype properties, whether they are built-in function objects or our own custom functions. 2. There is no difference between a stereotype object and a normal object except for its properties. Different stereotypes contain different property names, but by default, they all share the common property name constructor.

Question: How does an instance object call its prototype methods (we call callable properties on objects methods) since it doesn’t have a Prototype property on it? This brings us to the __proto__ attribute.

__proto__ properties

All objects have it__proto__Property, also known as an implicit stereotype, points to the stereotype of the function that created the object. If it sounds too convoluted, go straight to the picture above:

Then the code starts:

function Person() {} var person = new Person(); console.log(person.__proto__ === Person.prototype); //true console.log(Array.__proto__ === Function.prototype); //trueCopy the code

All objects have a __proto__ attribute. As a special object, the Function should also have this attribute. The code above shows that the implicit prototype of the built-in Array Function points to the prototype of Function, and the implicit prototype of our custom Function points to the prototype of our custom Function. But this only shows that the object’s __proto__ property is related to the function prototype that created the object. It doesn’t specify how to call the methods on the prototype. Don’t panic, please keep reading.

Access to object properties

function Person (name, age) { this.name = name; this.age = age; } Person.prototype.getInfo = function() { console.log(this.name,this.age); } let person = new Person("xm",18); person.getInfo(); //xm 18 person.getInfo = function() { console.log("none"); } person.getInfo(); //noneCopy the code

With the code above, we seem to know something really big. If you’re smart enough to remember, yes, under certain conditions, instance objects can read properties or methods on the prototype via the __proto__ property.

So accessing object properties is not as easy as we think, and the rules are as follows: 1. When accessing an object property, use its own property if the object has the property itself. 2. Otherwise, use the __proto__ attribute to find if it exists on the prototype object. If so, return this attribute. We call this chain, which can be traced up through the __proto__ attribute, a prototype chain.

But, the use of__proto__It is controversial and discouraged (modifying the behavior of a prototype in this way also affects performance). Because it was never included in the ECMAScript language specification, modern browsers implement it.__proto__Properties have been standardized in the ECMAScript 6 language specification to ensure Web browser compatibility. The object.getProtoTypeof method is now preferred.

See how convenient the prototype is, we can write some common properties and methods on the function prototype, when we want to call the instance object public method, we do not need to write a method for each instance, saving unnecessary memory consumption. Of course, you can also add methods to individual instances, depending on your preference.

The constructor property

Finally, don’t forget the constructor attribute. ** By default, each stereotype object has a constructor property, which points to the stereotype object’s constructor itself. As usual, above:The ** code is as follows:

function Person() {} let person = new Person(); console.log(Person.prototype.constructor === Person); //true console.log(person.constructor.name); //PersonCopy the code

In the origin of the prototype, I also said that the **constructor property is used to identify the type of the object, letting us know which function created the object. In the above code, since the Person instance itself has no constructor attribute, the __proto__ attribute is used to find the prototype of Person, and the constructor attribute is found above, and the result is returned.

Pay attention to the point

So that’s enough of the general stuff, and now I’m going to tell you something special. In JS, most Function implicit stereotypes point to Function stereotypes. What about Function implicit stereotypes? A prototype is an Object, but when you access properties that don’t exist in the Object itself, you look at the prototype, and the implicit prototype of the prototype points to the prototype of Object, so what does the implicit prototype of Object point to? Take a look at the following code:

// The Array Function has no constructor attribute. And the constructor attribute points to Function console.log(array.constructor === Function); //true // the implicit prototype of Function refers to the prototype of Function, which is added automatically when the JS engine starts. It is special to exist console.log(function.__proto__ === function.prototype); New Object console.log(function.prototype. __proto__ === object.prototype); //true console.log((new Object()).__proto__ === Object.prototype); //true // The implicit prototype of the Object prototype points to null console.log(object.prototype.__proto__); //nullCopy the code

Maybe you are still dizzy after watching the brain, not afraid, I give you a picture of the ultimate version:Let me get you straight again:1. The white arrows represent the prototype of the function, and they all point to the prototype of their respective function. 2. The green arrow represents calling a function with the new operator. 3. The blue arrows represent implicit prototype pointing, which is what we call the __proto__ attribute. It is the chain of archetypes that we always refer to, and access to object properties is also found in the order of this chain.

Special attention!! Function.__proto__ === function. prototype //true. __proto__ === null //true).

conclusion

All right, so much for stereotypes and stereotype chains, but that only solves the problem of instance objects calling common methods and properties. This is not the end of the story, because there are drawbacks to the inheritance of the prototype chain. Listen to next time on decomposition, object inheritance in JS.

Thank you very much. If you have any problems with my way of expression, please point them out and I will try my best to make changes. Thanks again, manual bow!