Four rules
Let's first understand the following four rules for reference types:
1. Reference types have object properties, which can be extended freely.
2. Reference types have an implicit prototype__ proto__ Property. The property value is an ordinary object.
3. Reference types, implicit prototypes__ proto__ The property value of points to the explicit prototype prototype property value of its constructor.
4. When you try to get a property of an object, if the object itself does not have this property, it will go to its implicit prototype__ proto__ (that is, the explicit prototype of its constructor).
Reference types: Object, Array, Function, Date, RegExp. Here I'll call proto implicit prototype for the time being. There is no official Chinese name. Most of us shout nonsense.
Let's verify the above rules one by one, and we will slowly understand the prototype and prototype chain.
Rule one
Reference types, all of which have object properties, can freely extend attributes:
const obj = {} const arr = [] const fn = function () {} obj.a = 1 arr.a = 1 fn.a = 1 console.log(obj.a) // 1 console.log(arr.a) // 1 console.log(fn.a) // 1 Copy code
This rule should be easy to understand. Date and RegExp are the same, so I won't repeat it.
Rule 2
Reference types have an implicit prototype__ proto__ Property. The property value is a common object:
const obj = {}; const arr = []; const fn = function() {} console.log('obj.__proto__', obj.__proto__); console.log('arr.__proto__', arr.__proto__); console.log('fn.__proto__', fn.__proto__); Copy code
Rule three
Reference types, implicit prototypes__ proto__ The property value of points to the explicit prototype property value of its constructor:
const obj = {}; const arr = []; const fn = function() {} obj.__proto__ == Object.prototype // true arr.__proto__ === Array.prototype // true fn.__proto__ == Function.prototype // true Copy code
Rule 4
When you try to get a property of an object, if the object itself does not have this property, it will go to its implicit prototype__ proto__ (that is, the explicit prototype of its constructor):
const obj = { a:1 } obj.toString // ƒ toString() { [native code] } Copy code
First of all, obj Object does not have toString attribute. The reason why it can obtain toString attribute is to follow the fourth rule and obtain it from the prototype of its constructor Object.
A special case
I'm trying to overturn the above rule. Look at the following code:
function Person(name) { this.name = name return this // In fact, this line can not be written, and the this object is returned by default } var nick = new Person("nick") nick.toString // ƒ toString() { [native code] } Copy code
Normally, nick , is an instance generated by the Person , constructor, but the prototype , of Person , does not have a toString method, so why can nick , get the toString method?
Here comes the concept of prototype chain. The nick instance reviews itself from its own point of view and finds that there is no toString method. If you can't find it, go up and find the prototype attribute of the Person constructor, but you still can't find it. The prototype # of the constructor is also an Object. The constructor of the Object is Object, so we found Object ToString method under prototype.
The above search process forms the concept of prototype chain, and the prototype chain I understand is such a process. I don't know who said that everything in JavaScript is an object. From the above situation, it seems to be such a reason. 🤔
A picture
Describe the prototype chain with pictures:
The last null is designed to avoid dead loop, object The implicit prototype of prototype} points to null.
A method
The instanceof operator is used to test whether the prototype property of the constructor appears anywhere in the object prototype chain. A simple handwritten version of instanceof , as follows:
// The prototype of variable R exists in the prototype chain of variable L function instance_of (L, R) { // If the validation is a basic data type, it directly returns false const baseType = ['string', 'number', 'boolean', 'undefined', 'symbol'] if(baseType.includes(typeof(L))) { return false } let RP = R.prototype; // Take the display prototype of R L = L.__proto__; // Take the implicit prototype of L while (true) { if (L === null) { // Find the top layer return false; } if (L === RP) { // Strict equality return true; } L = L.__proto__; // Not found. Continue to look up the prototype chain } } Copy code
Let's look at the following code:
function Foo(name) { this.name = name; } var f = new Foo('nick') f instanceof Foo // true f instanceof Object // true Copy code
The above code judgment process is roughly as follows:
1. f instanceof Foo: implicit prototype of f +__ proto__ And foo Prototype is equal, so it returns true.
2. f instanceof Object: implicit prototype of f +__ proto__ , and object Prototype # doesn't wait, so keep going up. Implicit prototype of f +__ proto__ Point to foo Prototype, so continue to use foo prototype.__ proto__ To compare object Prototype, now it's equal, because foo A prototype {is an ordinary object.
last
Because there are too many documents, in order to avoid affecting everyone's reading experience, only part of the contents are shown here in screenshots, detailed and complete JavaScript interview question documents, or More front-end information can be obtained here for free.
]
[external chain picture transferring... (img-6hLpwXgC-1627005985720)]
Because there are too many documents, in order to avoid affecting everyone's reading experience, only part of the contents are shown here in screenshots, detailed and complete JavaScript interview question documents, or More front-end information can be obtained here for free.