6

I was developing a small JS library and was to use there custom Error exceptions.

So, I decided to inherit them (ORLY?) from native Javascript Error object in this way:

var MyError = function(){
    Error.prototype.constructor.apply(this, arguments);
};

// Inherit without instantiating Error
var Surrogate = function(){};
Surrogate.prototype = Error.prototype;
MyError.prototype = new Surrogate();

// Add some original methods
MyError.prototype.uniqueMethod = function(){...}

Looks like usual inheritance.. But!

var err = new MyError("hello! this is text!");
console.log(err.message); // is giving me empty string!

I have read articles about this here and on MDN, but all of them saying me to use something like this:

var MyError = function(msg){
    this.message = msg;
};

But my question is - if not in the constructor of Error, then where message is initialized? May be somebody knows how Error native constructor works?

Thanks!

P.S. If it interesting - I was developing Enum.js library.

2
  • 1
    Making it as simple as possible: var obj = new Error(); Error.call(obj, "Hello, world!"); This doesn’t work either. Error is weird.
    – Ry-
    Commented Jul 8, 2013 at 15:57
  • 1
    @minitech: "Error is weird." +1 Commented Jul 8, 2013 at 16:01

1 Answer 1

5

What you're doing is fine. It's Error that's the problem.

On this line:

Error.prototype.constructor.apply(this, arguments);

...you're calling Error (indirectly) as a normal function call rather than as part of a new expression, and the defined behavior for Error when you call it as a non-constructor function is to create a new, blank Error and return it (rather than populating this).

Now, in the normal case, what you're doing with the prototype would make the standard check for whether it was called as a constructor (if (this instanceof Error)) work. Unfortunately, it doesn't seem to be doing that, and whatever check it uses to determine how it was called doesn't seem to be immediately amenable to what you're trying to do. Even this (which is just a test, not meant to be something you'd actually do):

MyError.prototype = Error.prototype; // You wouldn't normally do this, it's just a test

...didn't solve it.

This answer to another Stack Overflow question points to a possible workaround (basically, let Error create the object and then return that from MyError):

function MyError(message) {
    var e = new Error(message);
    // ...apply your enhancements to `e`
    return e;
}

Not amazingly satisfying as you'd have to put your extensions directly on the object rather than use the prototype chain, but if Error refusees to play ball, your options are a bit limited...

2
  • Thanks for answer. So, seems I need to do smth like: `MyError = function(msg){ var err = new Error(); this.msg = msg; this.stack = err.stack; ...} Commented Jul 8, 2013 at 16:07
  • @gobwas: I just updated the answer with one possible workaround. I don't like it, but I'm not sure you get a lot of choice. Edit Or, yeah, you could do it that way around. Commented Jul 8, 2013 at 16:08

Not the answer you're looking for? Browse other questions tagged or ask your own question.