Intro

Javascript hoisting is something you should know about because it’s one of those things that Javascript just decides to do and not tell you… like when your dog poops in the spare bedroom and doesn’t tell you and you find out when your in-laws show up like 3 weeks later for the holidays and judge you for your lack of attention to detail and then it’s awkward the whole time they are there because you know they are looking for more (figurative) dog poop that you didn’t clean up yet and you’re not even sure if they know what a run-on sentence even is!

Javascript Hoisting for Simple-Minded People (like me)

The good news is that hoisting isn’t that hard to understand. It’s just kind of weird and leaves you asking “why?”. I’m sure there is a perfectly reasonable explanation for why hoisting exists in the first place. Like maybe something to do with, I don’t know, like Neil Armstrong landing on the moon and NASA scientists could only write the lunar-lander software correctly if Javascript would hoist its variables. It’s gotta be something like that I would assume. But, no matter. It is a thing and you need to understand it and be aware of it in your code.

So what is hoisting?

In its simplest form, hoisting is the fact that Javascript moves (or hoists) all variable declarations to the top of its scope, regardless of where you define them in your code. First let’s take a look at an example of Javascript doing what we’d expect it to do.

1
2
3
var say = 'Arrr Matey';

console.log(say); // logs 'Arrr Matey'

No surprises here. Everything seems to work as expected, right? Just for poops and giggles, what happens when you delete line 1?

1
2
console.log(say);
// logs 'Uncaught ReferenceError: say is not defined'

Ok, again… this is understandable. Uncaught ReferenceError: say is not defined because well, we never declared or defined that variable. You’re catching on quick!

Not so fast. Here comes some hoisting action. Let’s declare and define say below the console.log and see what happens.

1
2
3
console.log(say); // logs 'undefined'

var say = 'Arrr Matey';

All we did here is switch the order of the 2 lines from the original example. Now when we log say we get undefined. Why is this weird, you ask? Because console.log seems to be aware of the reference to the variable say, it just doesn’t know what its value is. This is a different error than when we didn’t declare or define say at all.

What’s happening is that Javascript is hoisting the variable declaration (but not the definition) to the top of the scope. Take a look at what Javascript actually does to our code, behind the scenes, before it reads it.

1
2
3
4
5
var say;

console.log(say); // logs 'undefined'

say = 'Arrr Matey';

So if we extend this example out one more step, we can see the full order of events.

1
2
3
4
5
6
7
var say;

console.log(say); // logs 'undefined'

say = 'Arrr Matey';

console.log(say); // logs 'Arrr Matey'

So the fully articulated example above is the same as writing the short-hand version like this:

1
2
3
4
5
console.log(say); // logs 'undefined'

var say = 'Arrr Matey';

console.log(say); // logs 'Arrr Matey'

Hoisting with Function Expressions vs Function Declarations

Before I got hooked on the syntactical crack cocaine of Coffeescript, I only wrote Javascript using function declarations (e.g. function funcName(){}). I never saw the need to use function expressions (e.g. var funcName = function(){}), and never understood the difference or why anyone should choose one over the other. To be honest, there still isn’t a really good reason to choose one over the other (unless you have to support IE <9), but I do enjoy the uniformity of function expressions being treated as variables and adhering to the rules of hoisting that I have become familiar with. That is to imply that function declarations do not adhere to the rules of hoisting as seen in the following example:

1
2
3
4
5
6
7
say();

function say(){
    console.log('Arrr Matey');
}

// logs 'Arrr Matey'

With function declarations, you can invoke the function before it is defined. I suppose this could be a good thing (e.g. when used for code organization). But it can definitely be a bad and confusing thing if you’re not careful.

Here is the same example using a function expression:

1
2
3
4
5
6
7
say();

var say = function(){
    console.log('Arrr Matey');
}

// logs 'say is not a function'

Javascript doesn’t yet know that say is defined as a function. All it knows is that the variable say exists, because it has hoisted its declaration to the top of the scope.

Conclusion

That’s it. That’s all hoisting is and does. So yeah, just remember that the dog is probably going to poop in the guest room and he is definitely not going to tell you about it. Be aware of it so you have time to clean it up before your in-laws arrive — or perhaps before your next peer code review!