I decided that I’m going to start dumping some of the more obscure knowledge I’ve obtained about JavaScript onto my blog, partly for my own sake so I can maintain a written history and partly to help others learn some cool, interesting, or nasty things about the language.

This first article is going to be about code lifting, and it can lead to some very confusing results in the code of the unwary. Consider the following code. Think about it and figure out what will be logged to the console.

var a = 45;

var weirdness = function () {

   var transmogrify = function (val) {
      console.log(val);
      return val * 3.14159;
   }
   
   // What value gets passed to the transmogrify() function?  
   a = transmogrify(a);
   
   /*
    * Now we declare a locally scoped 'a' variable and set 
    * its value to 'a' plus an object literal
    */
   var a = a + {};

   return a;
}

console.log(weirdness());

What our common sense might say about the value of the ‘val’ parameter in the transmogrify() function would be 45 since we declare ‘a’ as a global variable and the weirdness() function would use that value since we don’t declare to locally scoped variable of the same name until later. Then, just to show a little weirdness in JavaScript, I’m adding an object to the value of ‘a’.

var a = a + {};

Just a quick diversion into this little bit of the Strange & Unusual. You might expect JavaScript to throw an exception here; perhaps a Type exception since ‘a’ (whatever its value) and an object literal are clearly different types. Well, our common sense just doesn’t apply here as the actual result is the two values simply concatenated into a string.

For example, if the right operand value of ‘a’ is 42, then the resulting value of ‘a’ would be “42[object Object]“… weird.

Anyway, back to what I call code lifting.

The value of the ‘val’ argument will actually be ‘undefined’ in this example instead of 45. This is because the declaration of variable (i.e. using var) gets lifted to the top of the function code by JavaScript. As a shorter example.

var b = 12;
sample = function () {
   b = b + 1;
   var b = 0;
}

is equivalent to

var b = 12;
sample = function () {
   var b;       // With no assignment, defaults to undefined
   b = b + 1;
   b = 0;
}

Something similar happens to functions. Any function you declare with var will have the variable lifted to the top of the function, but the function definition does not go with with. Conversely, if you define a function without using a var declaration, the entire function gets lifted. Because of that, in the following example first() will not be executed – and instead throw a TypeError because first was declared but is undefined – but second() will.

fire = function () {
   try {
      first();
   } catch (ex) {
      console.log(ex);
   }
   second();

   var first = function () {
      console.log('First!');
   };

   function second () {
      console.log('Second!');
   }
}

fire();