In-depth understanding of the JavaScript prototype chain - about the prototype, __ proto __, constructor those relationships may not completely get to know you

Speaking of the prototype chain, look at this blog Chuojin students must not unfamiliar, this is one of the most core JavaScript features. Then, a prototype chain in the end what is, what it works? This is discussed in this article content

For the prototype chain, so we can understand each JavaScript object, there is an internal property, we call [[prototype]] (Note, [[prototype]] property is not the prototype property here, for the prototype property we will be mentioned later) , this internal property will point to another object, and another object existence of such a property, ultimately, in Object.propotype end of the object above, so far, we have formed a so-called prototype chain

Prototype chain has such a feature: when a property or method to access the current object, if not visit in the current object, will always go up along the prototype chain until you find the corresponding attributes not found, returns undefined . When we attribute of an object writes, if the property exists in the prototype chain of high-rise, high-rise at this time it will not affect the property will only act on the current object, this feature we call shelter. For example, the following code

var parent={
    name:1
};
var son=Object.create(parent);
console.log(son.name);//输出1
son.name=2;
console.log(son.name);//输出2
console.log(parent.name);//输出1

As indicated above, the Object.create construct a son object attribute will point to the parent object [[the prototype]], at this time, although no son name attribute, but we can obtain a value obtained son.name, and when when we change the name of the attribute son, son will act directly above, to form a shielding property, will not have an impact parent

But the problem is that most people understand the prototype for the chain, it is just stay here and think for a property, if the property already exists in the high-rise [[prototype]] chain, then assign it, will always be cause shadowing, but in fact, this is wrong , there is also a lot of details we need a great atmosphere

About shelter

For shading objects, in fact, that the following three cases

1, if the name of a named data access properties in the [[prototype]] senior chain is found somewhere, and not marked as read-only, so named for the name of the property will write directly on the current object and forming a shading property. First piece of code lifted above example we can prove this conclusion

2, if a property named name is found at the top somewhere [[prototype]] chain, but it is marked as read-only (writeable: false), then set the property name or create shadowing property on the current object, are is not allowed, we can look at the following example

var parent={
    name:1
};
Object.defineProperty(parent,'name', {writable: false});

var son=Object.create(parent);
son.name=2;
console.log(son.name);//非严格模式下输出1
console.log(parent.name);//非严格模式下输出1

By the above code, we found that when the object name attribute son writes, was silent ignored, not just parent's name can not be written, or even can not be obscured. In fact, if the strict mode, perform son.name = 2, error directly. So no matter under what circumstances, when a high-rise property [[prototype]] chain is set to a non-writable state, shadowing effects disappear

3. If a property named name is found at the top [[prototype]] chain, but it is a setter, then the setter is always called, no new name attribute will be added to the current object, That is, the shielding effect at this time does not appear we look at the example below,

var parent = {
    _name:'test'
};

Object.defineProperty(parent, 'name', {
    get: function () {
        return this._name
    }, set: function (value) {
        this._name+=value//传入的值与this._name相加
    }
});

var son = Object.create(parent);
son.name = '2';
console.log(son.name);//输出'test2'
console.log(parent.name);//输出'test'
console.log(son.hasOwnProperty('name'));//false

If this time we do not call hasOwnProperty verify, it may be that the name attribute has produced a shelter, but in fact did not, the reason why the final name of the values ​​are different, because the setter is always called, and this points to a difference in terminology , it should be noted that, although the name attribute shelter did not happen, but it happened _name property is sheltered, which is the cause of the difference

Get on the prototype chain

When it comes to the above, a basic prototype chain is present in the object inside the property, we call [[prototype]], since it is inside the property, it means that we can not get to it directly. However es5 provides a standard method for obtaining [[prototype]], correct posture as follows

Object.getPrototypeOf(son)

Given the [[prototype]] are not read-only, so we can change the point prototype chain of the following methods, but it is strongly recommended to use. In fact, we generally should not change the existing target of a [[prototype]]

Object.setPrototypeOf(son,parent2);

To es6, es6 will __proto__ property before standardization part of the browser support, now we can directly use in es6 son .__ proto__ to access the [[prototype]], see the following code, then execute the console output is true

console.log(Object.getPrototypeOf(son)==son.__proto__)//true

About prototype property

First look again, prototype attribute is not equal to [[prototype]] , prototype property exists only in function, but [[prototype]] present in all subjects, although both occasionally point to the same place, but not the same A thing.

MDN has this to say on to explain:

Each instance of an object (object) has a private property (called the __proto__) pointing to its prototype object constructor ( the prototype  ). The prototype object has its own prototype object (__proto__), up until the layer of the prototype for an object  null. By definition, null no prototype, and as the prototype chain last link in. Almost all the objects are located in JavaScript Object instance of the top strand of the prototype.

We can understand these words, all the objects [[prototype]] points to its constructor's prototype, and prototype constructor is an object, but also the prototype chain, because all objects are as examples of Object by Object constructed, it is in fact the prototype chain will point to all of Object.prototype, ultimately, Object.prototype of [[prototype]] will point to null, finally ended.

So first we draw a conclusion Benpian: prototype property function can be understood as an example of public properties of the function, each function (called Foo Bar) after being new new, and examples of the prototype chain will point Foo.prototype. And, only in that the function prototype, in an ordinary subject, there is no prototype property

Interspersed with a little science

Here, we look at the way science, all the objects are instances of Object function, this is very easy to understand, can be seen from a new way to target

var myObj=new Object();

And all the functions are examples of the Function function, we usually declare a function like this

function test(){
alert('test');
}

But in fact we can write like this

var test=new Function('alert("test")');

Both versions of the effect is the same, however, so write only to explain why all of the functions are examples Function, the actual development process is strongly not recommended to do so will cause difficulties in maintenance.

This explains why so all objects will eventually point to Object.prototype. The Object itself is a function, so the Object .__ proto__ eventually point to the fact Function.prototype, but Function.prototype itself is an object, so Function.prototype prototype chain, that is, [[prototype]] final also point the Object.prototype, and here the end, pointing to null, ah, though a bit chaotic, but keep in mind the above conclusions, step by step derivation, it will not mess up

About constructor

Next, let's look at the following code

function MyConstructor(){
    this.test=1;
}
var myObj=new MyConstructor();
console.log(myObj.constructor.name);//MyConstructor

Intuitively, there is myObj instance there is a constructor property that points to its constructor, however, her face still came so fast, it's wrong, look at the following two outputs

console.log(myObj.hasOwnProperty('constructor'));//false
console.log(MyConstructor.prototype.constructor==myObj.constructor);//true

We found, in fact the constructor exists on MyConstructor.prototype, and this points to the value of the MyConstructor itself, myObj this instance of itself is not the constructor of this property, which is inherited from the prototype to the chain, which is a lot when we replace reason prototype lost when the constructor constructor

Here we come to the conclusion: constructor constructors points instance, and there on the prototype constructor

About instanceof

receiving a keyword instanceof left ordinary objects, the right to accept a function, it is often used to examine the relationship and instance constructors, e.g.

function MyConstructor(){
    this.test=1;
}
var myObj=new MyConstructor();
console.log(myObj instanceof MyConstructor);//true

But in fact, the code for the above purposes, instanceof the answer to the question is that in the entire [[prototype]] chain myobj of whether there have been any object, point to the MyConstructor.prototype

We look at the following code

var a={};
var b=Object.create(a);
function MyConstructor(){
    this.test=1;
}
MyConstructor.prototype=a;
console.log(b instanceof MyConstructor);//true

And it has nothing to do with the instance constructor, but instanceof does return true, so, for instanceof doing something very important to have a correct understanding

to sum up

Finally, attach the other blog authors to write a similar article summary chart, summary personally feel better, posted facilitate understanding of these concepts

If the above content is understood, then, personally feel that this figure should not be difficult to see to understand, there may be a few points would be more difficult to understand

1, on the Constructor Foo, we mentioned above, all of the constructor function when Function function, so Constructor Foo's nothing wrong with pointing Function, Foo .__ proto__ point Function.prototype is a matter of course

2, on the Function itself, or because all Function is the constructor function, so Function is its own constructor, in accordance with such understanding, the constructor Function point itself is not wrong, according to the rules prototype chain, Function .__ proto__ should pointing to its constructor, which is Function.prototype

3, on the Object, it being understood as a general function, then compare its prototype chain and Constructor's points and Foo look, in fact, very clear

 

References:

"You do not know js: this object prototype"

Inheritance and prototype chain

https://blog.csdn.net/cc18868876837/article/details/81211729

Guess you like

Origin blog.csdn.net/xiaomingelv/article/details/92170314