Reputation: 65603
I am seeing different behavior in Chrome vs Firefox and Safari for this code:
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") + '';
No errors are generated in strict mode. The error is caused by chrome calling the message getter with a different this object than expected.
Firefox/Safari output: "Error: fancy:hi"
Chrome output : "Error: fancy:undefined"
Any idea what is going on here?
Versions Tested
Chrome: 30.0.1599.69 OSX
Firefox: 24 OSX
Safari: 6.0.5 OSX
Upvotes: 2
Views: 345
Reputation: 116020
This definitely appears to be a bug in Chrome's 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");
With this setup in Chrome:
fe.message
produces fancy:I'm the instance
fe.toString()
produces Error: fancy:I'm the prototype
What happens in the first case is easy to understand:
fe.message
prompts a call to [[Get]]
on fe
with the argument "message"
[[Get]]
Step 1 gets the accessor descriptor set on fe
's prototype (since fe
does't have it's own message
property).[[Get]]
Step 6 calls the getter on the accessor descriptor, with this
set as the original object that called [[Get]]
(here, the fe
object).The second case is strange. It appears that fe.toString()
performs the [[Get]]
for "message"
on the Error
instance in fe
's prototype. This appears to be wrong, since Step 5 of Error.prototype.toString
specifies getting the message
from the this
value in the toString
function.
EDIT
I previously assumed that the problem was caused by fe
having Error
in its prototype chain. However, consider this case:
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");
In this case:
fe.message
is fancy:I'm the instance
as aboveError.prototype.toString.call(fe)
is Error: fancy:I'm the prototype
therefore, we must conclude that Chrome's Error.prototype.toString
mistakenly uses the prototype that contains the getter as the this
value of the getter
, which appears to contradict the normal behavior of [[Get]]
and/or Step 5 of Error.prototype.toString
.
Upvotes: 2