I am developing with JavaScript for a while and I am used to a lot of it quirks. But even after years of using this language you still find new curiosities. Today a struggled a while with this one.
Considering this piece of JavaScript code:

  1. var i = 10;
  2. function foo() {
  3.         i++; // i is now 11
  4.         console.log("foo1: "+i);
  5.         i = 0; // i is now 0
  6.         console.log("foo2: "+i);
  7. };
  8. console.log("global1: "+i); // should be 10
  9. foo();
  10. console.log("global2: "+i); // and now 0

Ok. That’s fine. Now we change the code a little bit to this one:

  1. var i = 10;
  2. function foo() {
  3.         i++; // is now 11
  4.         console.log("foo1: "+i);
  5.         var i = 0; //create a new variable with value 0
  6.         console.log("foo2: "+i);
  7. };
  8. console.log("global1: "+i); // expect: 10
  9. foo();
  10. console.log("global2: "+i); // expect: 11

What do you expect? I was quite surprised:

global1: 10
foo1: NaN
foo2: 0
global2: 10

Why do we get a Not a Number? Why is JavaScript not using the global var as in the first example? Why is the global variable i not increased, the operation took place before the declaration of the local variable i? JavaScript has some “strange” rules about variable declaration. Every variable declared within a function is initialised at the beginning of the function, so our function actually would look like this:

  1. var i = 10;
  2. function foo() {
  3.         var i; //undefined
  4.         i++; // undefined + 1 = NaN
  5.         console.log("foo1: "+i);
  6.         i = 0; //and now 0
  7.         console.log("foo2: "+i);
  8. };
  9. console.log("global1: "+i); //10
  10. foo();
  11. console.log("global2: "+i);//still 10, because global i has not changed

Looking into the rules of JSLint which helps to verify JavaScript code to improve the quality of your JavaScript you get a few rules how to safely declare variables:

  • JavaScript allows var definitions to occur anywhere within a function. JSLint is more strict.
  • JSLint expects that a var will be declared only once, and that it will be declared before it is used.
  • JSLint expects that a function will be declared before it is used.
  • JSLint expects that parameters will not also be declared as vars.
  • JSLint does not expect the arguments array to be declared as a var.
  • JSLint does not expect that a var will be defined in a block. This is because JavaScript blocks do not have block scope. This can have unexpected consequences. Define all variables at the top of the function.

So Remember: Variables are not initialised when they are declared!

Links:

  • all JSLint rules for quality JavaScript code.
  • WTFJS.com, a page collection all kinds of JavaScript curiosities.