对于此代码,我在Chrome与Firefox和Safari中看到了不同的行为:

var FancyError = function(x) { this.x = x; };
FancyError.prototype = new Error;

Object.defineProperties(FancyError.prototype, {
   'message': {
      'get': function(){ return "fancy:" + this.x; }
   }
});

new FancyError("hi") + '';


在严格模式下不会产生任何错误。该错误是由于Chrome使用与预期对象不同的此对象调用消息获取程序而导致的。

Firefox / Safari输出:"Error: fancy:hi"

Chrome输出:"Error: fancy:undefined"

知道这里发生了什么吗?

经过测试的版本

铬:30.0.1599.69 OSX

Firefox:24 OSX

Safari:6.0.5 OSX

最佳答案

这肯定是Chrome Error.prototype.toString中的错误:

var FancyError = function(x) { this.x = x; };
FancyError.prototype = new Error;
FancyError.prototype.x = "I'm the prototype";

Object.defineProperties(FancyError.prototype, {
   'message': {
      'get': function(){ return "fancy:" + this.x; }
   }
});

var fe = new FancyError("I'm the instance");


通过Chrome中的此设置:


fe.message产生fancy:I'm the instance
fe.toString()产生Error: fancy:I'm the prototype


第一种情况很容易理解:


fe.message使用参数[[Get]]提示在fe上调用"message"
[[Get]]步骤1获取在fe原型上设置的访问器描述符(因为fe没有它自己的message属性)。
[[Get]]步骤6调用访问器描述符上的getter,将this设置为调用[[Get]]的原始对象(此处为fe对象)。


第二种情况很奇怪。看来fe.toString()[[Get]]原型中的"message"实例上为Error执行fe。这似乎是错误的,因为Error.prototype.toString的第5步指定从message函数中的this值获取toString

编辑

我以前曾认为问题是由fe的原型链中包含Error引起的。但是,请考虑这种情况:

var FancyError = function(x) { this.x = x; };
FancyError.prototype.x = "I'm the prototype";

Object.defineProperties(FancyError.prototype, {
   'message': {
      'get': function(){ return "fancy:" + this.x; }
   }
});

fe = new FancyError("I'm the instance");


在这种情况下:


fe.message是上述的fancy:I'm the instance
Error.prototype.toString.call(fe)Error: fancy:I'm the prototype


因此,我们必须得出结论,Chrome的Error.prototype.toString错误地使用了包含吸气剂的原型作为thisgetter值,这似乎与[[Get]]和/或Error.prototype.toString的第5步的正常行为相矛盾。 。

10-04 16:45