Shading Javascript Prototype Properties and Object Properties

var person = { name :"dummy", personal_details: { age : 22, country : "USA" } }; var bob = Object.create(person); bob.name = "bob"; bob.personal_details.age = 23; console.log(bob.personal_details === person.personal_details); // true : since it does not shadow object of prototype object console.log(bob.name === person.name); // false : since it shadows name ////now bob.personal_details = {a:1}; console.log(bob.personal_details === person.personal_details); 

//Lying

When a bob object tries to override the person’s name property, then it will be obscured in the bob itself.

But in the case of personal_details , the same rule will be violated.

I am very curious to know why this is so.

Here is the jsbin link: http://jsbin.com/asuzev/1/edit

+6
source share
3 answers

What happens can be easily illustrated with a few examples:

Accessing personal_details files through the prototype chain

 var person = { name :"dummy", personal_details: { age : 22, country : "USA" } } var bob = Object.create(person) bob.name = "bob" bob.personal_details.age = 23 

What outputs:

 console.log( bob ); /// { name :"bob", personal_details: { age : 23, country : "USA" } } console.log( person ) /// { name :"dummy", personal_details: { age : 23, country : "USA" } } 

Age 23 is now set on the person object because bob.personal_details is a direct reference to person.personal_details through the bob prototype chain. When you navigate the structure of an object, you work directly with the person.personal_details object.


Overriding a prototyped property with a local property

However, if you override the bob personal_details property with another object, this prototype link will be overridden by a more local property.

 bob.personal_details = { a: 123 } 

Now the conclusion:

 console.log( bob ); /// { name :"bob", personal_details: { a : 123 } } console.log( person ) /// { name :"dummy", personal_details: { age : 23, country : "USA" } } 

So, turning to bob.personal_details - from now on you refer to the object { a: 123 } not the original { age : 23, country : "USA" } person’s object. All changes made will occur on this object and basically have nothing to do with the bob or person object.


Prototype chain

To keep things interesting, what do you think happens when you do this, after all of the above:

 delete bob.personal_details 

As a result, you restore the link of the original prototype to person.personal_details (because you deleted the added local property), so the console log will show:

 console.log( bob ); /// { name :"bob", personal_details: { age : 23, country : "USA" } } 

Basically, the JavaScript engine will work through the prototype chain until it finds the property or method that you request on each prototype object. A further chain defined by an element will mean that it will later redefine the rest.

Now another question: what happens if you run the following again:

 delete bob.personal_details 

Nothing, there is no longer the actual property assigned by bob called personal_details , delete will only work with the current object and will not follow the prototype chain.


Another way to look at it

Another way to look at how the prototype chain works is basically a stack of objects. When JavaScript scans a specific property or method, it will read down the following structure:

 bob : { } person : { name: 'dummy', personal_details: { age: 22 } } Object : { toString: function(){ return '[Object object]'; } } 

So for example, I would like to access bob.toString . toString is a method that exists on the base JavaScript Object , which is the base prototype for almost everything. When the interpreter receives a read request for a specific method or property for an object, it will follow this chain of events:

  • Does bob property called toString ? No.
  • Does bob.__proto__ ie person property called toString ? No.
  • Does bob.__proto__.__proto__ ie Object property called toString ? Yes
  • Return the link to function(){ return '[Object object]'; } function(){ return '[Object object]'; }

Once it reaches point 4, the interpreter will return a reference to the toString method found in Object. If the property was not found on Object , the undefined property error was most likely fired (since it is the last in the chain).

Now, if we take an example earlier and this time define the toString method on bob - like this:

 bob : { toString: function(){ return '[Bob]'; } } person : { name: 'dummy', personal_details: { age: 22 } } Object : { toString: function(){ return '[Object object]'; } } 

If we try to read the toString method on bob again, this time we get:

  • Does bob property called toString ? Yes.

The process stops at the first obstacle and returns the toString method from bob. This means that bob.toString() will return [Bob] , not [Object object] .

As Phant0m has been concisely stated, write requests for an object follow a different path and will never navigate the prototype chain. Understanding this is to determine the difference between what you read and what constitutes a write request.

 bob.toString --- is a read request bob.toString = function(){} --- is a write request bob.personal_details --- is a read request bob.personal_details = {} --- is a write request bob.personal_details.age = 123 --- is a read request, then a write request. 

The last element is one that causes confusion. And this process will follow this route:

  • Does bob property called personal_details ? No.
  • Does person property called personal_details ? Yes.
  • Return the link to { age: 22 } , which is stored somewhere in memory.

Now a new process begins, because each part of the navigation or assignment of an object is a new request for a property or method. So now we have our personal_details object, which we go to the write request, because the property or variable on the left has the side = equals is always an assignment.

  • Enter 123 into the age property of { age: 22 }

Thus, the initial request could be seen as something like this:

 (bob.personal_details) --- read (personal_details.age = 123) --- write 

If bob owned its own personal_details property, the process would be the same, but the target that was written would be different.


And finally ...

Share the lines of your question:

It is difficult to digest that the properties of prototype objects are considered as READ_ONLY, but if the property is an object, then you can master it and freely change its properties! Do I understand correctly?

Prototyped properties seem to be read-only, but only when directly accessing them as an object that inherits them, because these properties do not exist at all on the inheriting object. If you go to the prototype object itself, it can be processed in the same way as any normal object (with reading and writing), because this is exactly what it is - a normal object. This may be confusing at first, but it is the inheritance of nature or prototype, all about how you access the properties that you work with.

+10
source

In the second case, you do not assign the bob property, so how can you override it?

In the case of bob.name = "bob" you bind the bob owner’s own name.

In the second case, you do not. You get access to the bob personal_details property & ndash through the prototype. Then you assign a property to this object, by this time all connection to bob is lost.

Think of it this way:

 bob.personal_details.age = 23; // equivalent expr = bob.personal_details; expr.age = 23; // As you can see, there no assignment to bob 

This does not violate any rules, because the matter is completely different.

+3
source

I hope the diagram below is clear enough, but I will try to briefly explain what is happening.

When you create a new object using Object.create , you create an object with a prototype of the first argument to the create method. This way you create a bob with a prototype that points to the person object. All person properties are accessible via bob via the prototype link.

In the following image, you change the name bob . Now bob you just create a new slot or property of bob whose name is name (now the interpreter does not check the prototype chain when searching for the name property, it will directly find that bob has such a property).

In the third, you change bob.personal_details.age , which affects person.personal_details.age , because it's just the same object.

Finally, you set the personal_details property, now bob has a personal_details slot, this is not a prototype property, it is a reference to another object - anonymous.

enter image description here

+2
source

All Articles