Javascript, why would "this" be undefined in a bound node callback? - javascript

I'm encountering this error for the first time and I'm at a loss of what could cause it.
AccountController.create = function () {
var password = this.param('password'),
confirmPassword = this.param('confirmPassword'),
account = new Account(),
errorMessage = "",
errors = "",
error,
errorCount;
if (password !== confirmPassword) {
this.req.flash('warning', 'passwords do not match');
return this.redirect(this.urlFor({action: 'index'}));
}
account.email = this.param('email');
account.set('password', password);
account.name.first = this.param('name.first');
account.name.last = this.param('name.last');
account.access = this.param('access');
account.save(function (err, account, numberAffected) {
if (err) {
console.log("THIS: " + this);
errorMessage = "";
errors = err.errors;
if (!errors) {
errors = [{message: "There is already an account with this email address."}];
}
errorCount = errors.length;
for (error = 0; error < errorCount; error = error + 1) {
if (typeof errors[error] === "string") {
errorMessage += errors[error].message + " ";
}
}
this.req.flash('warning', errorMessage);
return this.redirect(this.urlFor({action: 'index'}));
}
return this.redirect(this.urlFor({controller: "profile", action: 'login'}));
}).bind(this);
};
I'm hoping that there's no additional code required to make the example work.
Console output (running via nodemon) looks like this:
THIS: undefined
/Users/crispensmith/Documents/cinchedStore/Site/app/controllers/account_controller.js:68
this.req.flash('warning', errorMessage);
^
TypeError: Cannot read property 'req' of undefined

You're doing .bind(this) on the return value of account.save, not the function you're passing into it. Just move the bind inside the bracket;
account.save((function // ... possibly also use an extra parenthesis
// ...
}).bind(this)); // to make the bind target more obvious?

Related

how can i avoid error "can't convert undefined to an object "

some of the document does not consists planDetails planId properties and its returning error "can't convert undefined to an object , but i have to fetch that document if these properties exists or not , how can i avoid this error
this.profile.find({ userId: ObjectId(req.id) }).populate("planId").lean().exec(function(err, profileFound) {
console.log(profileFound);
if (err) return callback(err);
if (profileFound && profileFound.length === 0) {
return callback(false, common.errorMsg("PROFILE DOES NOT EXIST"));
} else {
var profileData = profileFound[0];
profileData["isPlanTaken"] = false;
profileData["planDetails"] = {};
if(profileData.hasOwnProperty("planId") && profileData.planId){
if(Object.keys(profileData.planId).length>0){
profileData["isPlanTaken"]=true;
profileData["planDetails"]=profileData.planId;
}
}
return callback(
false,
common.successMsg("PROFILE FETCHED",profileData )
);
}
});
I think there was missing the initialization of profileData variable only...
const profileData = {};
profileData["isPlanTaken"] = false;
console.log(profileData);
profileData["planDetails"] = {};
if(profileData.hasOwnProperty("planId") && Object.keys(profileData.planId)){
profileData["isPlanTaken"]=true;
profileData["planDetails"]=profileData.planId;
}
console.log(profileData);
And I think that is also enough to check a property is exists in an object. Can you please give me more data for example, because I don't really know what do you need.
const profileData = {};
profileData.isPlanTaken = false;
console.log(profileData);
profileData.planId = 5; // for example
if (profileData.planId) {
profileData.isPlanTaken = true;
profileData.planDetails = profileData.planId;
}
console.log(profileData);

display few elements only for a particular user, not able to do it properly

it is showing error stating that not able to read the property "style".
i have seen many codes in similar way. i am not able to find the error.
function login()
{
var email = document.getElementById("email_field").value;
var password = document.getElementById("password_field").value;
firebase.auth().signInWithEmailAndPassword(email, password)
.then(user => {
console.log(user);
alert("Welcome " +email);
window.location.href = "Home.html";
if (email = "***#gmail.com"){
document.getElementById("gameurl").style.display="block";
document.getElementById("gameimg").style.display="block";
document.getElementById("gamename").style.display="block";
}else{
document.getElementById("gameurl").style.display="none";
document.getElementById("gameimg").style.display="none";
document.getElementById("gamename").style.display="none";
}
}).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
window.alert("Error : " + errorMessage);
});
}
Your if statement is bad. You need to use == or ===, but the one equals-sign means you're setting the variable, not comparing it.

Calling the filter method on a JQuery object is not working when done inside of a function

My knowledge of jQuery and more specifically javascript has always been very limited and I am working hard to get better.
With that in mind I am trying to create some sort of "extensible validation framework" in that I can create an object with a validation function and its error message, push it into an array and then call all those methods and report the messages from the ones that fail.
So first I did something very simple just to see that the basic validation worked which was this:
var selectedTourDate = $("#tourDate").val();
var list = $("#bookedTourDate *");
var isDateBooked = list.filter(function () {
return (this.innerHTML == selectedTourDate) ;
}).length !== 0;
if (isDateBooked) {
alert("Date invalid");
return;
}
This works fine.
Then I created my "framework" which is this:
function Validator(fn, errorMessage) {
this.validationFunction = fn;
this.errorMessage = errorMessage;
};
var validationRunner = {
validators: [],
errorMessages: [],
validationResult: true,
addValidation: function (validator) {
validationRunner.validators.push(validator);
},
validate: function () {
for (var validator = 0; validator < validationRunner.validators.length; validator++) {
if (validationRunner.validators[validator] instanceof Validator) {
var result = validationRunner.validators[validator].validationFunction();
validationResult = validationRunner.validationResult && result;
if (!result)
validationRunner.errorMessages.push(validationRunner.validators[validator].errorMessage);
}
}
},
getErrorMessage: function () {
var message = "<ul>";
for (var errorMessage = 0; errorMessage > validationRunner.errorMessages.length; errorMessage++) {
message += "<li>" + errorMessage + "</li>";
}
message += "</ul>";
return message;
}
}
And then modified the first block of code as follows:
var selectedTourDate = $("#tourDate").val();
var list = $("#bookedTourDate *");
var tmp = new Validator(function () {
return list.filter(function () {
return (this.innerHTML == selectedTourDate);
}).length !== 0;
}, "Date already booked");
validationRunner.addValidation(tmp);
validationRunner.validate();
var msg = validationRunner.getErrorMessage();
This does not work at all.
It seems that the problem is that in this statement:
return (this.innerHTML == selectedTourDate);
The "this" is the Validator object instead of the html element from the list which confuses me since as its inside the function of the "filter" method it should be.
Is there a way to correct this so I can accomplish what I am trying to do here?
this does have the correct value but there are some mistakes in the getErrorMessage function.
To check the value of this don't rely on a debugger's "watch variable" function but do a console.log which will give you the value at a specific point of the code execution.
My changes:
for (var errorMessage = 0; errorMessage < validationRunner.errorMessages.length; errorMessage++) {
message += "<li>" + validationRunner.errorMessages[errorMessage] + "</li>";
}
The errorMessage variable is only a index and not the actual error message. Also you used a "bigger than" instead of a "smaller than" sign.
Here's a fiddle
That is very odd, as this should be the current DOM element per jquery api.
The function should take an index as a parameter, though. So what about trying
return list.filter(function (i) {
return (list.get(i).innerHTML == selectedTourDate);
}).length !== 0;

How to respond to SyntaxError in javascript

I get data back from a php server and sometimes it tosses in warnings. These warnings cause the parsing of the response to throw a syntax error which defies all try/catch code I have in place and just stops processing, leaving complex objects in partial states that can't be recovered.
How can I catch these errors? I want to have a chance to get the object back into some steady state.
Ideally, I would not receive answers stating that I should rethink architecture or change php settings. I would like to know how to respond to SyntaxErrors being thrown by JSON.parse().
Thank you,
Jeromeyers
EDIT:
It has come to my attention that the problem is more complex than I originally thought. This is the code that doesn't catch the SyntaxError:
generateSubmissionSuccessCallback: function (reloadOnSave) {
var self = this;
var submissionCallback = function(response) {
var processingError = false;
try
{
var responseObject = {};
if (self.isAspMode())
{
if (typeof response !== 'object') // Chrome auto-parses application/json responses, IE & FF don't
{
response = JSON.parse(response);
}
responseObject = {
entity: response.Payload,
success: response.Success,
message: response.Exception
};
if (jQuery.isArray(response.ValidationErrors))
{
responseObject.message += ' \r\n\r\nValidation Errors\r\n';
for (var i = 0, maxi = response.ValidationErrors.length; i < maxi; i++)
{
var error = response.ValidationErrors[i];
responseObject.message += error.Error + '\r\n';
}
}
}
else
{
responseObject = JSON.parse(response);
}
if (!responseObject || (responseObject.success !== undefined && responseObject.success !== true))
{
processingError = true;
var message = responseObject ? responseObject.message : response;
ErrorHandler.processError(
'An attempt to save failed with following message: \r\n' + message,
ErrorHandler.errorTypes.clientSide,
null,
jQuery.proxy(self.validatingAndSubmittingFinallyFunction, self));
}
else
{
// If this is a parent metaform, reload the entity, otherwise, close the metaform
if (self.metaformType === 'details')
{
if (self.substituteWhatToDoAfterSavingCallback)
{
self.substituteWhatToDoAfterSavingCallback(responseObject);
}
else if (reloadOnSave)
{
self.reloadCurrentEntity(true, responseObject.entity);
}
if (self.doesViewOutlineDefinePostSaveHook())
{
self.viewOutline.functions.postSaveHook(self);
}
}
else if (self.metaformType === 'childDetails')
{
// Reload the Grid by which this form was made
if (self.associatedGridId)
{
Metagrid.refresh(self.associatedGridId);
}
if (self.parentMetaform.associatedGridId && self.childPropertyName)
{
var annotation = self.parentMetaform.getAnnotationByPropertyName(self.childPropertyName);
if (annotation && annotation.hasPropertyOptions('updateParentMetaformAssociatedGrid'))
{
Metagrid.refresh(self.parentMetaform.associatedGridId, self.parentMetaform.entityId);
}
}
if (self.substituteWhatToDoAfterSavingCallback)
{
if (self.doesViewOutlineDefinePostSaveHook())
{
self.viewOutline.functions.postSaveHook(self);
}
self.substituteWhatToDoAfterSavingCallback(responseObject);
}
else
{
if (self.doesViewOutlineDefinePostSaveHook())
{
self.viewOutline.functions.postSaveHook(self);
}
self.disposeMetaform();
}
}
}
}
catch (ex)
{
processingError = true;
ErrorHandler.processError(
"Please immediately inform the authorities that: \r\n\r\n" + typeof response === 'string' ? response : JSON.parse(response) + "\r\n\r\nand:\r\n\r\n " + ex.message,
ErrorHandler.errorTypes.clientSide,
null,
jQuery.proxy(self.validatingAndSubmittingFinallyFunction, self));
}
finally
{
// If we are reporting an error to the user then we can't reset these state variables
// because in the case where this is a child form, the parent will close the form
// before the user has read the error.
if (!processingError)
{
self.validatingAndSubmittingFinallyFunction();
}
}
};
return jQuery.proxy(submissionCallback, self);
}
There's really a lot going on in there, and a lot of structure that it fits into. I don't know if including it will really help.
Assuming you are talking about JSON and it raising an error (and not actual JavaScript being served to the page):
var data;
try{
data = JSON.parse(jsonString);
}catch(e){
// handle the error here, if you like
}
if (typeof data !== "undefined"){
// Yay, we got some!
}
Read more about try...catch at MDN.
For example (from Chrome's console):
> try{ JSON.parse('3/') }catch(e){ console.log('oh no!') }; console.log('OK!')
"oh no!"
"OK!"

How do I create a custom Error in JavaScript?

For some reason it looks like constructor delegation doesn't work in the following snippet:
function NotImplementedError() {
Error.apply(this, arguments);
}
NotImplementedError.prototype = new Error();
var nie = new NotImplementedError("some message");
console.log("The message is: '"+nie.message+"'")
Running this gives The message is: ''. Any ideas as to why, or if there is a better way to create a new Error subclass? Is there a problem with applying to the native Error constructor that I don't know about?
Update your code to assign your prototype to the Error.prototype and the instanceof and your asserts work.
function NotImplementedError(message = "") {
this.name = "NotImplementedError";
this.message = message;
}
NotImplementedError.prototype = Error.prototype;
However, I would just throw your own object and just check the name property.
throw {name : "NotImplementedError", message : "too lazy to implement"};
Edit based on comments
After looking at the comments and trying to remember why I would assign prototype to Error.prototype instead of new Error() like Nicholas Zakas did in his article, I created a jsFiddle with the code below:
function NotImplementedError(message = "") {
this.name = "NotImplementedError";
this.message = message;
}
NotImplementedError.prototype = Error.prototype;
function NotImplementedError2(message = "") {
this.message = message;
}
NotImplementedError2.prototype = new Error();
try {
var e = new NotImplementedError("NotImplementedError message");
throw e;
} catch (ex1) {
console.log(ex1.stack);
console.log("ex1 instanceof NotImplementedError = " + (ex1 instanceof NotImplementedError));
console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
console.log("ex1.name = " + ex1.name);
console.log("ex1.message = " + ex1.message);
}
try {
var e = new NotImplementedError2("NotImplementedError2 message");
throw e;
} catch (ex1) {
console.log(ex1.stack);
console.log("ex1 instanceof NotImplementedError2 = " + (ex1 instanceof NotImplementedError2));
console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
console.log("ex1.name = " + ex1.name);
console.log("ex1.message = " + ex1.message);
}
The console output was this.
undefined
ex1 instanceof NotImplementedError = true
ex1 instanceof Error = true
ex1.name = NotImplementedError
ex1.message = NotImplementedError message
Error
at window.onload (http://fiddle.jshell.net/MwMEJ/show/:29:34)
ex1 instanceof NotImplementedError2 = true
ex1 instanceof Error = true
ex1.name = Error
ex1.message = NotImplementedError2 message
This confirmes the "problem" I ran into was the stack property of the error was the line number where new Error() was created, and not where the throw e occurred. However, that may be better that having the side effect of a NotImplementedError.prototype.name = "NotImplementedError" line affecting the Error object.
Also, notice with NotImplementedError2, when I don't set the .name explicitly, it is equal to "Error". However, as mentioned in the comments, because that version sets prototype to new Error(), I could set NotImplementedError2.prototype.name = "NotImplementedError2" and be OK.
In ES2015, you can use class to do this cleanly:
class NotImplemented extends Error {
constructor(message = "", ...args) {
super(message, ...args);
this.message = message + " has not yet been implemented.";
}
}
This does not modify the global Error prototype, allows you to customize message, name, and other attributes, and properly captures the stack. It's also pretty readable.
Of course, you may need to use a tool like babel if your code will be running on older browsers.
All of the above answers are terrible awful - really. Even the one with 107 ups! The real answer is here guys:
Inheriting from the Error object - where is the message property?
TL;DR:
A. The reason message isn't being set is that Error is a function that returns a new Error object and does not manipulate this in any way.
B. The way to do this right is to return the result of the apply from the constructor, as well as setting the prototype in the usual complicated javascripty way:
function MyError() {
var temp = Error.apply(this, arguments);
temp.name = this.name = 'MyError';
this.message = temp.message;
if(Object.defineProperty) {
// getter for more optimizy goodness
/*this.stack = */Object.defineProperty(this, 'stack', {
get: function() {
return temp.stack
},
configurable: true // so you can change it if you want
})
} else {
this.stack = temp.stack
}
}
//inherit prototype using ECMAScript 5 (IE 9+)
MyError.prototype = Object.create(Error.prototype, {
constructor: {
value: MyError,
writable: true,
configurable: true
}
});
var myError = new MyError("message");
console.log("The message is: '" + myError.message + "'"); // The message is: 'message'
console.log(myError instanceof Error); // true
console.log(myError instanceof MyError); // true
console.log(myError.toString()); // MyError: message
console.log(myError.stack); // MyError: message \n
// <stack trace ...>
//for EMCAScript 4 or ealier (IE 8 or ealier), inherit prototype this way instead of above code:
/*
var IntermediateInheritor = function() {};
IntermediateInheritor.prototype = Error.prototype;
MyError.prototype = new IntermediateInheritor();
*/
You could probably do some trickery to enumerate through all the non-enumerable properties of the tmp Error to set them rather than explicitly setting only stack and message, but the trickery isn't supported in ie<9
If anyone is curious on how to create a custom error and get the stack trace:
function CustomError(message) {
this.name = 'CustomError';
this.message = message || '';
var error = new Error(this.message);
error.name = this.name;
this.stack = error.stack;
}
CustomError.prototype = Object.create(Error.prototype);
try {
throw new CustomError('foobar');
}
catch (e) {
console.log('name:', e.name);
console.log('message:', e.message);
console.log('stack:', e.stack);
}
class NotImplementedError extends Error {
constructor(message) {
super(message);
this.message = message;
}
}
NotImplementedError.prototype.name = 'NotImplementedError';
module.exports = NotImplementedError;
and
try {
var e = new NotImplementedError("NotImplementedError message");
throw e;
} catch (ex1) {
console.log(ex1.stack);
console.log("ex1 instanceof NotImplementedError = " + (ex1 instanceof NotImplementedError));
console.log("ex1 instanceof Error = " + (ex1 instanceof Error));
console.log("ex1.name = " + ex1.name);
console.log("ex1.message = " + ex1.message);
}
It is just a class representation of this answer.
output
NotImplementedError: NotImplementedError message
...stacktrace
ex1 instanceof NotImplementedError = true
ex1 instanceof Error = true
ex1.name = NotImplementedError
ex1.message = NotImplementedError message
This section of the standard may explain why the Error.apply call doesn't initialize the object:
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.
In this case the Error function probably determines that it's not being called as a constructor, so it returns a new Error instance rather than initializing the this object.
Testing with the following code seems to demonstrate that this is in fact what's happening:
function NotImplementedError() {
var returned = Error.apply(this, arguments);
console.log("returned.message = '" + returned.message + "'");
console.log("this.message = '" + this.message + "'");
}
NotImplementedError.prototype = new Error();
var nie = new NotImplementedError("some message");
The following output is generated when this is run:
returned.message = 'some message'
this.message = ''
I like to do it like this:
Make use of name so toString() throws "{code}: {message}"
Return same thing to super so it appears the same in the stacktrace
Attach code to error.code as checking/parsing a code is better in code than checking a message, which you might want to localize for example
Attach message to error.message as an alternative to error.toString()
class AppException extends Error {
constructor(code, message) {
const fullMsg = message ? `${code}: ${message}` : code;
super(fullMsg);
this.name = code;
this.code = code;
this.message = fullMsg;
}
toString() {
return this.message;
}
}
// Just a code
try {
throw new AppException('FORBIDDEN');
} catch(e) {
console.error(e);
console.error(e.toString());
console.log(e.code === 'FORBIDDEN');
}
// A code and a message
try {
throw new AppException('FORBIDDEN', 'You don\'t have access to this page');
} catch(e) {
console.error(e);
console.error(e.toString());
console.log(e.code === 'FORBIDDEN');
}
function InvalidValueError(value, type) {
this.message = "Expected `" + type.name + "`: " + value;
var error = new Error(this.message);
this.stack = error.stack;
}
InvalidValueError.prototype = new Error();
InvalidValueError.prototype.name = InvalidValueError.name;
InvalidValueError.prototype.constructor = InvalidValueError;
Accoring to Joyent you shouldn’t mess with the stack property (which I see in lots of answers given here), because it will have a negative impact on performance. Here is what they say:
stack: generally, don't mess with this. Don't even augment it. V8 only computes it if someone actually reads the property, which improves performance dramatically for handlable errors. If you read the property just to augment it, you'll end up paying the cost even if your caller doesn't need the stack.
I like and would like to mention their idea of wrapping the original error which is a nice replacement for passing on the stack.
So here is how I create a custom error, considering the above mentioned:
es5 version:
function RError(options) {
options = options || {}; // eslint-disable-line no-param-reassign
this.name = options.name;
this.message = options.message;
this.cause = options.cause;
// capture stack (this property is supposed to be treated as private)
this._err = new Error();
// create an iterable chain
this.chain = this.cause ? [this].concat(this.cause.chain) : [this];
}
RError.prototype = Object.create(Error.prototype, {
constructor: {
value: RError,
writable: true,
configurable: true
}
});
Object.defineProperty(RError.prototype, 'stack', {
get: function stack() {
return this.name + ': ' + this.message + '\n' + this._err.stack.split('\n').slice(2).join('\n');
}
});
Object.defineProperty(RError.prototype, 'why', {
get: function why() {
var _why = this.name + ': ' + this.message;
for (var i = 1; i < this.chain.length; i++) {
var e = this.chain[i];
_why += ' <- ' + e.name + ': ' + e.message;
}
return _why;
}
});
// usage
function fail() {
throw new RError({
name: 'BAR',
message: 'I messed up.'
});
}
function failFurther() {
try {
fail();
} catch (err) {
throw new RError({
name: 'FOO',
message: 'Something went wrong.',
cause: err
});
}
}
try {
failFurther();
} catch (err) {
console.error(err.why);
console.error(err.stack);
console.error(err.cause.stack);
}
es6 version:
class RError extends Error {
constructor({name, message, cause}) {
super();
this.name = name;
this.message = message;
this.cause = cause;
}
[Symbol.iterator]() {
let current = this;
let done = false;
const iterator = {
next() {
const val = current;
if (done) {
return { value: val, done: true };
}
current = current.cause;
if (!val.cause) {
done = true;
}
return { value: val, done: false };
}
};
return iterator;
}
get why() {
let _why = '';
for (const e of this) {
_why += `${_why.length ? ' <- ' : ''}${e.name}: ${e.message}`;
}
return _why;
}
}
// usage
function fail() {
throw new RError({
name: 'BAR',
message: 'I messed up.'
});
}
function failFurther() {
try {
fail();
} catch (err) {
throw new RError({
name: 'FOO',
message: 'Something went wrong.',
cause: err
});
}
}
try {
failFurther();
} catch (err) {
console.error(err.why);
console.error(err.stack);
console.error(err.cause.stack);
}
I’ve put my solution into a module, here it is: https://www.npmjs.com/package/rerror
I had a similar issue to this. My error needs to be an instanceof both Error and NotImplemented, and it also needs to produce a coherent backtrace in the console.
My solution:
var NotImplemented = (function() {
var NotImplemented, err;
NotImplemented = (function() {
function NotImplemented(message) {
var err;
err = new Error(message);
err.name = "NotImplemented";
this.message = err.message;
if (err.stack) this.stack = err.stack;
}
return NotImplemented;
})();
err = new Error();
err.name = "NotImplemented";
NotImplemented.prototype = err;
return NotImplemented;
}).call(this);
// TEST:
console.log("instanceof Error: " + (new NotImplemented() instanceof Error));
console.log("instanceof NotImplemented: " + (new NotImplemented() instanceofNotImplemented));
console.log("message: "+(new NotImplemented('I was too busy').message));
throw new NotImplemented("just didn't feel like it");
Result of running with node.js:
instanceof Error: true
instanceof NotImplemented: true
message: I was too busy
/private/tmp/t.js:24
throw new NotImplemented("just didn't feel like it");
^
NotImplemented: just didn't feel like it
at Error.NotImplemented (/Users/colin/projects/gems/jax/t.js:6:13)
at Object.<anonymous> (/Users/colin/projects/gems/jax/t.js:24:7)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:487:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
The error passes all 3 of my criteria, and although the stack property is nonstandard, it is supported in most newer browsers which is acceptable in my case.
I used the Constructor Pattern to create the new error object. I defined the prototype chain such as an Error instance. See the MDN Error constructor reference.
You can check this snippet on this gist.
IMPLEMENTATION
// Creates user-defined exceptions
var CustomError = (function() {
'use strict';
//constructor
function CustomError() {
//enforces 'new' instance
if (!(this instanceof CustomError)) {
return new CustomError(arguments);
}
var error,
//handles the arguments object when is passed by enforcing a 'new' instance
args = Array.apply(null, typeof arguments[0] === 'object' ? arguments[0] : arguments),
message = args.shift() || 'An exception has occurred';
//builds the message with multiple arguments
if (~message.indexOf('}')) {
args.forEach(function(arg, i) {
message = message.replace(RegExp('\\{' + i + '}', 'g'), arg);
});
}
//gets the exception stack
error = new Error(message);
//access to CustomError.prototype.name
error.name = this.name;
//set the properties of the instance
//in order to resemble an Error instance
Object.defineProperties(this, {
stack: {
enumerable: false,
get: function() { return error.stack; }
},
message: {
enumerable: false,
value: message
}
});
}
// Creates the prototype and prevents the direct reference to Error.prototype;
// Not used new Error() here because an exception would be raised here,
// but we need to raise the exception when CustomError instance is created.
CustomError.prototype = Object.create(Error.prototype, {
//fixes the link to the constructor (ES5)
constructor: setDescriptor(CustomError),
name: setDescriptor('JSU Error')
});
function setDescriptor(value) {
return {
configurable: false,
enumerable: false,
writable: false,
value: value
};
}
//returns the constructor
return CustomError;
}());
USAGE
The CustomError constructor can receive many arguments to build the message, e.g.
var err1 = new CustomError("The url of file is required"),
err2 = new CustomError("Invalid Date: {0}", +"date"),
err3 = new CustomError("The length must be greater than {0}", 4),
err4 = new CustomError("Properties .{0} and .{1} don't exist", "p1", "p2");
throw err4;
And this is how the custom error looks:
This is my implementation:
class HttpError extends Error {
constructor(message, code = null, status = null, stack = null, name = null) {
super();
this.message = message;
this.status = 500;
this.name = name || this.constructor.name;
this.code = code || `E_${this.name.toUpperCase()}`;
this.stack = stack || null;
}
static fromObject(error) {
if (error instanceof HttpError) {
return error;
}
else {
const { message, code, status, stack } = error;
return new ServerError(message, code, status, stack, error.constructor.name);
}
}
expose() {
if (this instanceof ClientError) {
return { ...this };
}
else {
return {
name: this.name,
code: this.code,
status: this.status,
}
}
}
}
class ServerError extends HttpError {}
class ClientError extends HttpError { }
class IncorrectCredentials extends ClientError {
constructor(...args) {
super(...args);
this.status = 400;
}
}
class ResourceNotFound extends ClientError {
constructor(...args) {
super(...args);
this.status = 404;
}
}
Example usage #1:
app.use((req, res, next) => {
try {
invalidFunction();
}
catch (err) {
const error = HttpError.fromObject(err);
return res.status(error.status).send(error.expose());
}
});
Example usage #2:
router.post('/api/auth', async (req, res) => {
try {
const isLogged = await User.logIn(req.body.username, req.body.password);
if (!isLogged) {
throw new IncorrectCredentials('Incorrect username or password');
}
else {
return res.status(200).send({
token,
});
}
}
catch (err) {
const error = HttpError.fromObject(err);
return res.status(error.status).send(error.expose());
}
});
I just had to implement something like this and found that the stack was lost in my own error implementation. What I had to do was create a dummy error and retrieve the stack from that:
My.Error = function (message, innerException) {
var err = new Error();
this.stack = err.stack; // IMPORTANT!
this.name = "Error";
this.message = message;
this.innerException = innerException;
}
My.Error.prototype = new Error();
My.Error.prototype.constructor = My.Error;
My.Error.prototype.toString = function (includeStackTrace) {
var msg = this.message;
var e = this.innerException;
while (e) {
msg += " The details are:\n" + e.message;
e = e.innerException;
}
if (includeStackTrace) {
msg += "\n\nStack Trace:\n\n" + this.stack;
}
return msg;
}
The constructor needs to be like a factory method and return what you want. If you need additional methods/properties, you can add them to the object before returning it.
function NotImplementedError(message) { return new Error("Not implemented", message); }
x = new NotImplementedError();
Though I'm not sure why you'd need to do this. Why not just use new Error... ? Custom exceptions don't really add much in JavaScript (or probably any untyped language).
This is implemented nicely in the Cesium DeveloperError:
Docs
Source
In it's simplified form:
var NotImplementedError = function(message) {
this.name = 'NotImplementedError';
this.message = message;
this.stack = (new Error()).stack;
}
// Later on...
throw new NotImplementedError();
At the expense of not being able to use instanceof, the following preserves the original stack trace and doesn't use any non-standard tricks.
// the function itself
var fixError = function(err, name) {
err.name = name;
return err;
}
// using the function
try {
throw fixError(new Error('custom error message'), 'CustomError');
} catch (e) {
if (e.name == 'CustomError')
console.log('Wee! Custom Error! Msg:', e.message);
else
throw e; // unhandled. let it propagate upwards the call stack
}
Another alternative , might not work in all enviroments.Atleast assured it works in nodejs 0.8
This approach uses a non standard way of modifying the internal proto prop
function myError(msg){
var e = new Error(msg);
_this = this;
_this.__proto__.__proto__ = e;
}
If you are using Node/Chrome. The following snippet will get you extension which meets the following requirements.
err instanceof Error
err instanceof CustomErrorType
console.log() returns [CustomErrorType] when created with a message
console.log() returns [CustomErrorType: message] when created without a message
throw/stack provides the information at the point the error was created.
Works optimally in Node.JS, and Chrome.
Will pass instanceof checks in Chrome, Safari, Firefox and IE 8+, but will not have a valid stack outside of Chrome/Safari. I'm OK with that because I can debug in chrome, but code which requires specific error types will still function cross browser. If you need Node only you can easily remove the if statements and you're good to go.
Snippet
var CustomErrorType = function(message) {
if (Object.defineProperty) {
Object.defineProperty(this, "message", {
value : message || "",
enumerable : false
});
} else {
this.message = message;
}
if (Error.captureStackTrace) {
Error.captureStackTrace(this, CustomErrorType);
}
}
CustomErrorType.prototype = new Error();
CustomErrorType.prototype.name = "CustomErrorType";
Usage
var err = new CustomErrorType("foo");
Output
var err = new CustomErrorType("foo");
console.log(err);
console.log(err.stack);
[CustomErrorType: foo]
CustomErrorType: foo
at Object.<anonymous> (/errorTest.js:27:12)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:906:3
/errorTest.js:30
throw err;
^
CustomErrorType: foo
at Object.<anonymous> (/errorTest.js:27:12)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:906:3
The following worked for me taken from the official Mozilla documentation Error.
function NotImplementedError(message) {
var instance = new Error(message);
instance.name = 'NotImplementedError';
Object.setPrototypeOf(instance, Object.getPrototypeOf(this));
if (Error.captureStackTrace) {
Error.captureStackTrace(instance, NotImplementedError);
}
return instance;
}
NotImplementedError.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
Here is my solution for supporting pre-es2015 browsers. It does not do any fancy prototype tweaking and will not break debuggers.
/** Custom Errors
// Depends on underscore js
// This will declare an CustError() class in both 'this' and '_exports' namespaces
// ctor is optional
declare_cust_error(function CustError(){}, {ns: [this, _exports], ctor:
function cust_err_ctor(instance, clazz, name, msg, info){
q$.called(arguments)
}
})
// Usage:
// Second param (pojso) is optional
try {
throw CustError.create("foo", {k1: 'v1', k2: 'v2'})
}catch(ex){
if(CustError.is_inst(ex)){
console.error("its a CustError", ex)
} else {
throw ex
}
}
**/
function declare_cust_error(error_class, opts){
var p, c, cp
if(!error_class||!(p=error_class.prototype))throw new Error("error_class must be a Class")
try{
c = p.constructor; cp = c.toString()
}catch(ex){}
if(!cp || cp.indexOf('function ') != 0 || cp.indexOf('[native code]') > 0)
throw new Error("error_class must be a classic proto class (pre-es6) but got: " + error_class.toString())
opts=opts||{}
error_class.__is_cust_error__ = true
error_class.__cust_error_name__ = c.name
error_class.create = function cust_error_create(msg, info){
var instance = new Error(msg)
instance.info = info
instance.__is_cust_error__ = true
instance.__cust_error_name__ = c.name
if(_.isFunction(opts.ctor)){
opts.ctor(instance, error_class, c.name, msg, info)
}
return instance
}
error_class.is_inst = function cust_error_is_inst(instanace){
return ( (instanace instanceof Error) && instanace.__cust_error_name__ === error_class.__cust_error_name__ )
}
// Declare error in namespace(s)
_.each(_.isArray(opts.ns)?opts.ns:[opts.ns], function(ns){ ns[c.name] = error_class })
return error_class
}
A lot of the methods above won't work.
The last one is an actual error. If you use a string, it looks good, but it doesn't give a stack trace. If you throw with Error, you can't have "Uncaught BadError: bad", so you'll have to remove the custom error (sadly). If you throw an object, it looks kind of off, and the final one is just an average error.
This method creates an error with a custom name while preserving stack tracing:
var errProto = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
})
var isFirefox = !!window.InstallTrigger
// Hide stack for Firefox only, as stacks can cause problems with high "frame" counts.
function createError(name, message, hideStack) {
if (message == null) {
message = ""
}
var customError = Error(message)
customError.name = name
Object.setPrototypeOf(customError, errProto)
if (isFirefox && hideStack) {
customError.stack = ""
} else if (isFirefox) {
var stack = customError.stack
var newline = stack.indexOf("\n") + 1
stack = stack.slice(newline)
customError.stack = stack
var split = stack.split(":")
if (split.length > 4) {
var a = split[3]
var b = split[4]
var t = b.slice(0, b.indexOf("\n"))
customError.lineNumber = Number(a)
customError.columnNumber = Number(t)
}
} else {
var stack = customError.stack
var split = stack.split("\n")
var secondPart = split.slice(2).join("\n")
stack = split[0] + "\n" + secondPart
customError.stack = stack
var split = secondPart.split(":")
var a = split[2]
var b = split[3]
}
throw customError
}
var frame = 0
function aFunction() {
if (++frame === 100) {
createError("LazyError", "function getting lazy", false, true)
} else {
requestAnimationFrame(aFunction)
}
}
setTimeout(aFunction, Math.random() * 500)
* {
font-family: Verdana;
}
Check your inspector!
Try a new prototype object for each instance of the user defined error type. It allows instanceof checks to behave as usual plus type and message are correctly reported in Firefox and V8 (Chome, nodejs).
function NotImplementedError(message){
if(NotImplementedError.innercall===undefined){
NotImplementedError.innercall = true;
NotImplementedError.prototype = new Error(message);
NotImplementedError.prototype.name = "NotImplementedError";
NotImplementedError.prototype.constructor = NotImplementedError;
return new NotImplementedError(message);
}
delete NotImplementedError.innercall;
}
Note that an additional entry will preceed the otherwise correct stack.
This is fastest way to do it:
let thisVar = false
if (thisVar === false) {
throw new Error("thisVar is false. It should be true.")
}
easier way. You could make your object inherit from the Error object.
Example:
function NotImplementError(message)
{
this.message = message;
Error.call();
Error.call(message);
}
what we are doing is using the function call() which call the constructor of the Error class so is basicly the same thing as implementing a class inheritance in other object oriented languages.
MDN has an excellent example:
try {
throw new Error('Whoops!');
} catch (e) {
console.log(e.name + ': ' + e.message);
}

Categories

Resources