Reputation: 5201
I have observed a behaviour regarding __proto__
which seems weird to me: when changing __proto__
to various objects it behaves as expected, but once it is set to null
changing it again to another object doesn't seem to have an effect.
Is this a bug in the implementation, or the desired behaviour? If this is the desired behaviour, can someone shed a light as to why?
An example JavaScript code (all the tests pass fine until the last line):
p = {
sum: function() {
return this.x + this.y;
}
};
o = {
x: 1,
y: 2
};
o.sum(); // As expected: TypeError: o.sum is not a function
// These all behave as expected:
o.__proto__ = p;
o.__proto__; // [object Object]
o.__proto__.sum; // [object Function]
o.sum(); // returns 3 :-)
// These all behave as expected:
o.__proto__ = {};
o.__proto__; // [object Object]
o.sum(); // TypeError: o.sum is not a function
// These all behave as expected:
o.__proto__ = p;
o.__proto__; // [object Object]
o.__proto__.sum; // [object Function]
o.sum(); // returns 3 :-)
// Still behaves more or less as expected:
o.__proto__ = null;
o.__proto__; // undefined (why undefined and not null?)
o.sum(); // TypeError: o.sum is not a function
// Seems fine, until the last line:
o.__proto__ = p;
o.__proto__; // [object Object]
o.__proto__.sum; // [object Function]
o.sum(); // Expected 3, but... TypeError: o.sum is not a function
I'm working with Firefox 28.0; don't know how other browsers react.
Upvotes: 4
Views: 185
Reputation: 10972
The issue is that __proto__
in Firefox is an actual property on Object.prototype
implemented with getter/setter
functions. So when you set the __proto__
of o
to null
, you wiped out the entire prototype chain, which included the __proto__
property.
Now when you assign to __proto__
, you're just assigning a new, normal property that doesn't have the desired behavior directly to the o
object.
So in order to get the functionality of __proto__
, you'll need to go to Object.prototype
, and borrow the .set
method of the __proto__
property, and use .call
to allow it to operate on the o
object.
Object.getOwnPropertyDescriptor(Object.prototype, "__proto__").set.call(o, p);
So this invokes the set
function of Object.prototype.__proto__
using .call
so that the o
becomes the this
value of set
, and p
is the value being set. This will make __proto__
operate on o
as though it was a property of o
, allowing it to set the internal [[Prototype]]
property.
Note that this is only tested in Firefox.
Upvotes: 3