Reputation: 1333
I have an custom error object that is extending the Error object:
function GTError(reason, loglevel, meta) {
winston.log(loglevel, reason, meta);
GTError.super_.apply(this, arguments);
}
util.inherits(GTError, Error);
I know that this doesn't work, and this question has workarounds for that. My question isn't how to work around it, my question is why doesn't it work? Why does calling GTError.super_.apply(this, arguments);
(where GTError.super_
is Error
) not populate the message
property of the this
?
can you explain, please? Thanks
Upvotes: 1
Views: 127
Reputation: 1074038
My question isn't how to work around it, my question is why doesn't it work?
Because the Error
function always returns a new instance, even if you don't call it with new
; it doesn't modify the object this
refers to when you call it. From the ES5 specification:
When
Error
is called as a function rather than as a constructor, it creates and initialises a newError
object. Thus the function callError(…)
is equivalent to the object creation expressionnew Error(…)
with the same arguments.
So in your code, GTError.super_.apply(this, arguments);
(where GTError.super_
is Error
) is effectively a no-op, because it creates and throws away an Error
object rather than making Error
populate the object passed as this
. In fact, there's no way (in ES5) to make Error
populate the object created by new
in your new GTError
expression, because of the way Error
was defined.
The TC-39 committee fixed that in ES2015, but only when you're using the new class stuff (in order to maintain backward compatibility).
I know you said you just wanted to know why, but for others: In ES2015 and later, you can correctly subclass Error
via the new class
stuff. This syntax is supported in at least Node v4 in strict mode, and universally in Node v6. The following will work in any recent version of Chrome or Firefox:
let winston = {
log: function(...args) {
console.log("log", ...args);
}
};
class GTError extends Error {
constructor(reason, loglevel, meta) {
winston.log(loglevel, reason, meta);
super(reason, loglevel, meta);
}
}
try {
throw new GTError("reason", 10, "meta");
}
catch (e) {
console.log(e instanceof Error);
console.log(e instanceof GTError);
console.log(e.message);
}
Upvotes: 1