Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
597 views
in Technique[技术] by (71.8m points)

javascript - __proto__ doesn't seem to work after a null assignment - bug or feature?

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...