I seem to miss something about the constructor chain inheritance in Javascript, with native objects. For example :
function ErrorChild(message) { Error.call(this, message); }
ErrorChild.prototype = Object.create(Error.prototype);
var myerror = new ErrorChild("Help!");
Why myerror.message
is defined as ""
after those statements ? I would expect the Error constructor to define it as "Help!" (and override the default value of Error.prototype.message
), like if I was doing :
var myerror = new Error("Help!")
Thanks a lot !
When it comes to inheritance, JavaScript only has one construct: objects. Each object has a private property which holds a link to another object called its prototype. That prototype object has a prototype of its own, and so on until an object is reached with null as its prototype.
The Prototypal Inheritance is a feature in javascript used to add methods and properties in objects. It is a method by which an object can inherit the properties and methods of another object. Traditionally, in order to get and set the [[Prototype]] of an object, we use Object. getPrototypeOf and Object.
In JavaScript, an object can inherit properties of another object. The object from where the properties are inherited is called the prototype. In short, objects can inherit properties from other objects — the prototypes.
The difference between classical inheritance and prototypal inheritance is that classical inheritance is limited to classes inheriting from other classes while prototypal inheritance supports the cloning of any object using an object linking mechanism.
The simple work-around: Working fiddle
function ErrorChild(name, message) {
// Error.call(this); this is not needed
this.name = name;
this.message = message;
}
ErrorChild.prototype = Object.create(Error.prototype);
ErrorChild.prototype.constructor = ErrorChild;
var myerror = new ErrorChild("test", "Help!");
document.body.innerHTML += myerror.message;
The above doesn't break the expected behaviour. When you throw myerror
, the correct name
and message
will display.
The problem
From the ECMA5 Language Specification:
15.11.1 The Error Constructor Called as a Function
When Error is called as a function rather than as a constructor, it creates and initialises a new Error object. Thus the function call Error(...) is equivalent to the object creation expression new Error(...) with the same arguments.
The problem: Error.call(this)
, is the equivalent of new Error
. But the new Error
instantiation will not set the name
or message
. new Error
will initialise message
with ""
by default.
15.11.4.3 Error.prototype.message # Ⓣ Ⓡ The initial value of Error.prototype.message is the empty String.
Test(proof)
If inside your ErrorChild
you were to add:
var test = Error.call(this, message);
console.dir(test);
console.log(test instanceof Error); // true;
console.log(test.message); // "Help!";
The test
reflects the ECMA5 spec. An Error
instance with a proper message
set.
Conclusion:
Because Error.call(arguments);
gets automatically translated to new Error(arguments);
scope is lost, so the properties are never initialised on the this
object.
When Object.create(Error.prototype)
is used, the message
property takes the default value, the empty String.
The Problem is not the inheritance chain, but rather the fact that calling Error
as a function behaves as calling the constructor, instantiating a new Error
Object
Therefore when calling your new ErrorChild
the code executed is actually equivalent to
function ErrorChild(message) {
new Error (message)
}
Wait. But this only creates a new Error Object which is not used anywhere (and also not returned by your constructor). And simply gets forgotten about.
So this actually doesn't modify your actual ErrorChild
instance.
Therefore the message
propertie you are accessing is the one shadowed by ErrorChild.prototype
which inherits from Error.protyotype
and therefore contains the message
's default value an Empty String ""
But you can "mimic" an Error Object simply.
As you only need the toString
method's defined behaviour and 2 properties
name
message
To cover the Error's standard properties.
You can simply set your constructors prototype to Error.prototype
And assign name
and message
manually.
function ErrorChild (name,message) {
this.name = name;
this.message = message;
}
ErrorChild.prototype = Error.prototype;
Now you can simply create a new ErrorChild (...)
instance.
Which you can throw
around log
and catch
->
throw new ErrorChild("CustomError","Help") //Uncaught CustomError: Help
Heres a JSBin Demo
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With