Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I deal with invalid input to an object constructor in JavaScript

I'm trying to get my head around OOP in Javascript (I've never really used OOP in any other language either, so this is my first experience of it). I've written a class that requires an input for the constructor, but the constructor only only works with a specifically formatted string.

I have a regex that I can use to check the input against, but I don't know what I am supposed to do if it doesn't match (or if there is no input at all). Should I throw an exception of some sort? If so, how do I go about that?

like image 780
Grezzo Avatar asked Oct 04 '12 16:10

Grezzo


4 Answers

In JavaScript, throwing exceptions is not what you want to do. An exception sould only occur exceptionally (duh...). This is in contrast to Java, where Exceptions are used all over the place for communication. The reason for this difference is that exception handling is awfully slow in JS.

So you may very well equip your constructor with a throw, but that is not supposed to be caught in production. You'd rather check validity first, outside the constructor.

Do:

if (validRE.test(input)) {
    foo = new MyObject(input);
} else {
    // show message to the user
}

Don't:

try {
    foo = new MyObject(input);
} catch (ex) {
    // show message to the user
}
like image 156
user123444555621 Avatar answered Oct 19 '22 22:10

user123444555621


JavaScript constructors (functions called with the new keyword) always need to return an object, you can't return false, null or similiar like when invoked normal. So, you have two options:

  • throw an exception from it. You can do so with every javascript value in a throw statement. Then, catch them outside the construction with a try statement
  • Return a usual object, but with the internal values set to a invalid pointer. The Date constructor does that for instance, getting attributes then results in NaNs.

Additionally (especially when using exceptions) you might provide an extra validation function (which returns boolean) as a static property on the constructor, so you can use that even before constructing an object. Example:

function Decryption(str) {
    if (! Decryption.test(str))
        throw new SyntaxError("invalid encryption");
    this.result = decrypt(str);
}
Decryption.test = function(str) {
    return /MyCoolRegExp/.test(str);
};
like image 39
Bergi Avatar answered Oct 19 '22 22:10

Bergi


If you want to throw an exception, you can do like this:

throw new Error("Illegal construction string.");

(The Error object isn't mandatory, i.e. you can throw a plain string, but it will make the error message show up nicely if you handle the onerror event.)

As you are going to use user input, you whould probably validate the string before calling the constructor, and give the user a friendlier message than the result of an exception. You can of course still have the validation in the constructor to make sure that nothing sneaks by.

like image 35
Guffa Avatar answered Oct 19 '22 23:10

Guffa


There's generally two ways you can go about this: either throw an exception, or return some value that indicates failure (like undefined). In JavaScript, I tend to lean more towards the latter, more forgiving approach.

I also find that the second approach more closely mimics a lot of JavaScript itself. For example, in Python, if you try to access a nonexistent attribute on an object, it'll throw an exception.

>>> foo = 0
>>> foo.idontexist
AttributeError: 'int' object has no attribute 'idontexist'

Whereas in JavaScript, it just returns undefined.

> var foo = 0;
> foo.idontexist
undefined

Many functions and objects work this way as well. For example, Date returns an Invalid Date object when passed an incorrect date string, instead of throwing an exception.

> var foo = new Date('thisisnotadate');
> foo
Invalid Date
like image 20
voithos Avatar answered Oct 19 '22 22:10

voithos