2014-05-07 26 views
3

我观察到一个关于__proto__的行为,这对我来说似乎很奇怪:当将__proto__更改为各种对象时,其行为与预期相同,但一旦将其设置为null,将其再次更改为另一个对象似乎没有效果。__proto__似乎无效后分配 - 错误或功能?

这是实施中的错误还是期望的行为?如果这是所期望的行为,有人可以阐明为什么吗?

一个例子JavaScript代码(所有的测试都通过了罚款,直到最后一行):

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 

我用Firefox 28.0工作;不知道其他浏览器如何反应。

+1

您究竟如何运行测试?我的意思是你不能在第一个TypeError之后继续测试,那么你是否再次使用该行注释掉了它? –

+0

@cookie:我在网络控制台上逐行运行它:) – Tom

+0

我看到它发生了。似乎只要您分配'。proto__ = null',原型继承在'o'上永久破坏。在重新分配'p'后,甚至不能使用'.hasOwnProperty()'等本地方法。虽然'__proto__'是非标准的,所以我不知道它可能被称为bug。 –

回答

2

问题是,Firefox中的__proto__Object.prototype上的一个实际属性,使用getter/setter函数实现。因此,当您将__proto__o设置为null时,您已消除整个原型链,其中包括__proto__属性。

现在当您分配给__proto__时,您只是将一个新的普通属性直接分配给o对象。


所以为了得到__proto__的功能,你需要去Object.prototype,并借用__proto__属性的.set方法,并使用.call允许它在o对象进行操作。

Object.getOwnPropertyDescriptor(Object.prototype, "__proto__").set.call(o, p); 

所以这个调用使用.call使得o成为setthis值的Object.prototype.__proto__set功能,并p是被设置的值。这将使__proto__o上运行,就好像它是o的一个属性,允许它设置内部[[Prototype]]属性。


请注意,这只在Firefox中测试。

+0

感谢您的解释 - 解决方案! – Tom

+0

不客气。 –

相关问题