Monday, November 3, 2014

A Taste of Java...script. Hoisting

Javascript has been getting some popularity lately, and it's not really a secret. I've posted some links to my Twitter feed of recent articles that I've read detailing node.js and using Javascript for full-stack dev. I'll post them here as well:
http://www.toptal.com/nodejs/why-the-hell-would-i-use-node-js
http://www.toptal.com/javascript/guide-to-full-stack-javascript-initjs

Interesting stuff. This just means that now - more than ever - we as software engineers need to know how Javascript works, and we need to know it well if we want to use it for full-stack development.
The strange thing about Javascript is that it's well...strange. Devs coming from a background in C++ or Java, or even Python will be surprised at some of the things Javascript takes for granted, like hoisting...

This should break, right?

Example 1:
console.log(square(2));
function square(x){
  return x*x;
}

but it doesn't. It produces 4 just like if you had written:

function square(x){
  return x*x;
}
console.log(square(2));

hmm....okay. So this works too then?
Example 2:
console.log(square(2));
var square = function(x){
  return x*x;
}

well...no, not at all. Example 1 runs perfectly, example 2 will generate an undefined reference error. So, what exactly is going on here?

In Javascript, there is something called variable hoisting, which applies to variables and functions, and basically moves them to the top of their enclosing scope (remember, in Javascript, functions define scope, not braces). This is because the Javascript compiler runs through the program first, allocates variables and references, and then the execution engine runs through and actually runs stuff. So in example 1, the compiler sees the function declaration, handles it, and then when the execution engine runs, it calls console.log(...) and finds the reference to the square function no problem. 
Cool, so why does example 2 fail?

Well, to answer that, here's example 3:
console.log(x);
var x = 3;

Works, right? Nah, it's an undefined reference error too.
The deal is that variable declarations are hoisted, but assignments are not, so in example 3, the compiler more or less produces:
var x;
console.log(x);
x = 3;

So it's obvious why it's an undefined reference. It's basically the same for example 2. The Javascript compiler will generate the following code for the execution engine:
var square;
console.log(square(2));
square = function(x){
return x*x;
}

So, hoisting can come in handy in many situations, but be wary of the fact that it can catch you off guard sometimes.