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
namemessageTo 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