ssj
ssj

Reputation: 1797

why property in prototype of an object can not modified by object?

When I execute the following js code, I found something weird:

function Contact(name, email) {
    this.name = name;
    this.email = email;
}

Contact.prototype = {
    a: 10,
    b: 20
};

var obj = new Contact('ssj', 'ssh');
obj.a = 'ssjssh';
console.log(obj);
console.log(Contact.prototype);
//output: { name: 'ssj', email: 'ssh', a: 'ssjssh' },{ a: 10, b: 20 }

so my question is that why obj.a = 'ssjssh' only add a property in obj, instead of change the property a in Contact.prototype?

Upvotes: 3

Views: 82

Answers (4)

Dmitri Pavlutin
Dmitri Pavlutin

Reputation: 19060

This is the way object properties are queried and modified.
Initially a is not an own property of the obj, but inherited (contrary to name and email, which are own properties). When querying it, the interpreter searches for the property in the prototype chain, and finds the a in the Contact.prototype.
When you assign a value to inherited a, JavaScript creates a new own property in the object, without affecting the prototype. Any later modifications of the own property do not affect the prototype. The inherited property will now be hidden.
If you would like to modify directly the prototype, just use Contact.prototype.a = 'new value'. But notice that this will affect all the instances of the Contact constructor, which use the inherited a property.
Use the method obj.hasOwnProperty('a') to check if the property is own or inherited.

Upvotes: 1

subi_speedrunner
subi_speedrunner

Reputation: 921

The statement var obj = new Contact('ssj', 'ssh'); will create a new object newObj (assume jst for reference) internally and it will return newobj.


Before returning newObj, the statement

this.name = name;
this.email = email;

will set the newObj's name & email property to 'ssj' & 'ssh' as because of implicit binding 'this' is bound to newobj.

Now after returning obj will point to newObj with values as name-'ssj' & email-'ssh'

After this you are creating a new property "a" on obj.

newObj which we created previously is pointing internally to Contact.prototype via [[prototype]] link. so newObj & Contact.prototype are both different object & you are setting property on newobj.

And by the concept of shadowing and a being not marked as read only it will not traverse up the prototype chain, instead it will set the a property directly on the immediate object.

Upvotes: 0

Zakaria
Zakaria

Reputation: 15070

From Eloquent Javascript by Marijn Haverbeke :

When you add a property to an object, whether it is present in the prototype or not, the property is added to the object itself, which will henceforth have it as its own property. If there is a property by the same name in the proto- type, this property will no longer affect the object. The prototype itself is not changed.

Upvotes: 2

Barmar
Barmar

Reputation: 780688

Properties in the prototype are only used as a default when reading them. This allows all the members of a class to get the same initial or default values for properties. But each object can override these default properties by having its own values. When you assign to the property, it always goes to the object's own properties, otherwise there wouldn't be any way to override the defaults.

Upvotes: 4

Related Questions