Three common mistakes in JavaScript / EcmaScript

Here are three common mistakes I've seen recently in script files.
  1. Undefined is not null, except that it is.
    If you've been writing code in a strongly-typed language recently, you're used to checking the nullity of objects before you use them, like this:

    if
    (SomeObject.foo !== null) {

    Well, in JavaScript, something that has not been assigned to is not null, it's undefined. Undefined is different from null when using !== but not when using the weaker != because JavaScript does some implicit casting in this case. Well, anyways, you can use typeof to explicitly check for undefined, or use the weaker equality operators, but the shortest way to deal with this, and also the one that best expresses your intention of checking if an object is safe to use is probably to just rely on the type-sloppiness of JavaScript and count on it to evaluate null and undefined as false in a boolean expression, like this:

    if
    (SomeObject.foo) {

    It's very important to keep the undefined case in mind. Another case is when you expect a function to return a boolean value. What if the function forgets to return a value in some cases? Well, its return value is then undefined, which is false. So if your own default value should be true, you should really write this:

    if
    (SomeFunction() !== false) {

    Which is different from if (SomeFunction()). By the way, note the strict equality here, which preserves you from strange things like "" == 0).
    But let me summarize and potentially add to the confusion before we move on to the next trick:
    undefined false
    (SomeObject.foo) false false
    (SomeObject.foo != null) false true
    (SomeObject.foo !== null) true true
    (SomeObject.foo != false) true false
    (SomeObject.foo !== false) true false
     
  2. You can't overload a function.
    Developers who are used to languages like Java and C# overload methods all the time. Well, in JavaScript, there are no overloads, and if you try to define one, you won't even get an error. The interpreter will just pick the latest-defined version of the function and call it. The earlier versions will just be ignored.
    The way you simulate overloading is twofold. First, if a parameter is omitted, it is undefined. And second, there is a special variable, arguments, which is an array of the function parameters. Based on the type of each parameter, you can do different things. But it's kind of ugly.
     
  3. Undeclared variables are global.
    Always, always declare your variables using the var keyword. If you don't, your variable is global. So anyone who makes the same mistake as you (or more likely, if you do the same mistake in two different places) will create nice conflicts which give rise to very difficult-to-track bugs. Even loop counters should be properly declared.
There is actually a good way to do some basic sanity checks on your script files (like multiple declarations, forgotten declarations, unassigned variables, etc.): in Firefox, go to the about:config url and look for the javascript.options.strict entry. Set it to true. Now, you can point the browser to your JavaScript file. You'll get a lot of new warnings that will point to the problems in your code (if any, but I doubt that you'll get zero warnings the first time you do that).
UPDATE: removed the useless rant at the beginning (I now quite like JavaScript) and corrected some mistakes in #1.

20 Comments

  • Manks thanks for explaining #1 -- I had been doing all my checks as != null and was mystified why they were failing.

  • #1 needs a little supplement though...



    example:

    the variable "val" does not yet exist.

    if you do :



    if ( val ) doSomething;

    else doElseThing;



    JavaScript will crash, because "val" does not exist, and does return neither "null" nor "undefined" nor "false".



    The workaround I use is :



    try { if ( val ) doSomething; } catch(e) { doElseThing; }



    If used often, consider using a function:



    function exist (a) {

    try { var b=a;}

    catch(e){return false;}

    return true;

    } // exist



    so you can just use:



    if ( exist (val) ) doSomething;

    else doElseThing;





    it's advisable to put all your code in :



    try { ... your code ... } catch (e) { alert (e); }



    browsers like FireFox will give a little detail on the problem when encountered.

  • Moonlite: while you are right that an undeclared variable will trigger a javascript error, I would certainly not encourage anyone to go ahead and include the test in a try/catch.

    The right workaround here is to declare all your variables, even if you don't initialize them immediately. In this case, they will undefined, but the test will not crash.

    There are very few cases where you need a try/catch. They do exist, but this is not one of them.

    Thanks for the heads up, though.

  • I like the:
    if(typeof(VariableName)=='undefined'){...}
    It works fine.

  • Jacco: sure, and that's why you should always use === instead of == which is so fuzzy it's really a useless bug factory.

    For more fun about undefined, read this:
    http://weblogs.asp.net/bleroy/archive/2006/08/02/Define-undefined.aspx

  • the solution was very helpful n awesome .
    It saved me .
    thnx a lot

  • Hi, nice post. only one thing:
    if (SomeObject)
    works fine on Firefox, but IE (6.0 at least) will raise a javascript error on the client. To prevent this, you can check for 'undefined' and 'unkown' using typeof(var):
    if (typeof(SomeObject)!="undefined" && typeof(SomeObject)!="unknown" && SomeObject)

  • Guido: right, there is the assumption here that the variable was declared.

  • what about:
    if (!someObject)

    is this true when someObject is null OR undefined, or just null?

  • @cis: sure, !someObject will be true for undefined and null.

  • I common misconception is that because JavaScript includes 'Java' in it's name, it will behave like Java (or C#). I feel it is really more like C than either of those languages.

    Though typing tends to default to string, which is peculiar to most languages, perhaps making it more like PHP.

  • @Attila: right, thanks, I fixed the post.

  • I just need to to say it sometimes:
    JAvascript is a nightmare of a computer language and I hate it.
    For how long will we have to suffer from this failure?

  • @Longyearbyen: well, JS is now pretty much the most popular language in the world and it doesn't look like anything can seriously challenge it anytime soon. I highly recommend Crockford's "JavaScript, the good parts" as a way to deal with it :)

  • In your very second line,
    if (SomeObject.foo) {

    SomeObject.foo might be a numeric type with the value 0. And the intent of the original code is to determine whether foo has been set. So your code doesn't do that.

    From a Jash session:
    >> 0?"first":"second"
    second
    >> 1?"first":"second"
    first
    >> null?"first":"second"
    second

  • @Simon: sure, hence the bold 'object' in the post.

  • if (!! foo) alert('Yo, foo is defined and not-null');

    if (! foo) alert('Yo, foo is undefined or null');

    The "!!" trick is most useful with an object:

    if (!! foo && foo.bar) {
    alert('Yo, foo is defined and foo.bar is like false');
    }

  • The bit about not supporting overloading was a big help, I wanted to put a function in a .js file which was brought in by a bunch of pages, but some of them may already have it defined locally and didn't know what the behavior would be. Thanks!

  • I would say that:
    if (SomeObject.foo) {

    IS a common mistake in Javascript.

    when your object is numerical and take the value ZERO, if (SomeObject.foo) would return FALSE.

    Consider this for exemple when trying to position the mouse in Opera versus Internet Explorer:

    if (window.pageXOffset) { //All browser except IE
    } else { //IE all version up to 8
    }

    in the case where window.pageXOffset got the value 0,
    this would fail.

    instead we should always use [typeof] when trying to find "undefined" or non existent property

    like:
    if (typeof(window.pageXOffset) != "undefined") {
    } else {
    }

    and don't forget, != is always faster then ==

  • @VbNetMatrix: yeah, which is why I said "the shortest way to deal with this, and also the one that best expresses your intention of checking if an object is safe to use is [...]", I even emphasized "object" to make it obvious you should only do this with an object. That is also why I added the !== example afterwards and warned about implicit conversions such as "" == 0.
    I also wrote a post on using typeof with undefined: http://weblogs.asp.net/bleroy/archive/2006/08/02/Define-undefined.aspx That was in 2006.

Comments have been disabled for this content.