Tales from the Evil Empire

Bertrand Le Roy's blog

News


Bertrand Le Roy

BoudinFatal's Gamercard

Tales from the Evil Empire - Blogged

Blogs I read

My other stuff

Archives

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.

Comments

freedumb fighter said:

Manks thanks for explaining #1 -- I had been doing all my checks as != null and was mystified why they were failing.
# February 24, 2005 12:36 PM

MoonLite said:

#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.
# March 5, 2005 11:55 AM

Bertrand Le Roy said:

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.
# March 7, 2005 1:32 PM

Jportelas said:

I like the: if(typeof(VariableName)=='undefined'){...} It works fine.
# October 12, 2006 11:10 AM

Bertrand Le Roy said:

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

# February 9, 2007 2:04 PM

coolestCompany said:

the solution was very helpful n awesome .

It saved me .

thnx a lot

# July 20, 2007 6:33 AM

Guido said:

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)

# January 18, 2008 10:54 AM

Bertrand Le Roy said:

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

# January 18, 2008 1:27 PM

cis said:

what about:

if (!someObject)

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

# February 29, 2008 1:19 PM

Bertrand Le Roy said:

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

# February 29, 2008 1:56 PM

James said:

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.

# April 23, 2008 12:08 AM

Bertrand Le Roy said:

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

# July 24, 2008 4:09 PM

Longyearbyen said:

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?

# October 27, 2008 10:47 AM

Bertrand Le Roy said:

@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 :)

# October 27, 2008 12:35 PM

Simon Arthur said:

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

# January 28, 2009 2:14 PM

Bertrand Le Roy said:

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

# January 28, 2009 2:39 PM

Yabeya said:

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');

}

# June 3, 2009 12:59 AM

Duane Taylor said:

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!

# July 15, 2009 5:23 PM

VbNetMatrix said:

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

# March 13, 2010 8:41 PM

Bertrand Le Roy said:

@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: weblogs.asp.net/.../Define-undefined.aspx That was in 2006.

# March 14, 2010 12:35 AM