Let's Talk About Hoisting

Feb 06, 2017

As it turns out, the concept of hoisting isn't actually that difficult to understand. As a simple description, hoisting is being able to access variables and functions before they are declared in your code. For example:

console.log(sayHello()); // => Hello World

function sayHello() {
  return 'Hello World';
}

Now, there is a difference between functions and variables. Where functions do exactly what they are "supposed" to do, variables act in a completely different way. How about another example:

console.log(hello); // => undefined

var hello = 'Hello World';

console.log(hello); // => Hello World

Why this different behavior you might ask? I'll explain it in a bit, but first let me explain a few things. One thing you'll probably read when looking into hoisting is "The functions and variable names are moved to the top of their scope so that they are accessible to you at runtime." Or some such nonsense. Let me give an example of what they're trying to say:

// Original Code
console.log(foo());
console.log(bar);

var bar = 'BAR';

function foo() {
  return 'FOO';
}


// Runtime Code
var bar;

function foo() {
  return 'FOO';
}

console.log(foo());
console.log(bar);

bar = 'BAR';

Let me respond to this with a big fat NO, your code is not physically moved to any other location in the file. Yes, I admit it is a good way of explaing the concept in an easy to understand way, but this is not what actually happens.

What really happens is there are 2 steps that the JavaScript engine is taking. First it compiles the code, then it runs the code. During compile time, functions and variables are saved to memory which makes them accessible during runtime. Remember when you asked why there is different behavior between functions and variables? Well when functions are stored in memory, the name as well as the entire function body is stored in memory. When a variable is stored in memory, just the variable name is stored and it is initialized to undefined until it is reassigned later during runtime. These differences are important to remember when you start talking about function declarations vs. function expressions. Yep, another example:

console.log(foo()); // => FOO
console.log(bar()); // => Uncaught TypeError: bar is not a function
console.log(foo); // => function foo(){return 'FOO'}
console.log(bar); // => undefined

// Function Declaration
function foo() {
  return 'FOO';
}

// Function Expression
var bar = function () {
  return 'BAR';
}

This difference is extremely important to understand. Where function declarations can be created anywhere in the current scope, and called from anywhere in the current scope (even before it was created), this is not the case with function expressions. Since they are actually just functions assigned to a variable, they cannot be used until after the variable has been initialized with the function expression. This changes the way you have to think about structuring your code and some would say it forces developers to write their code in a more logical order. I'm not going to get into my preference, I'll just say to know the difference before you make a decision.

That's pretty much all I have to say about hoisting. If I missed anything or I was just being a complete idiot and got things wrong, please let me know. I much prefer people to correct my mistakes rather than let me sound like an idiot wink.

ES2015 or ES6:

I almost forgot to mention, const and let do not work the same way var works. Where var is initialized to undefined, const and let are not. So if you try to use them before they are initialized you will get an error. Just something to remember if you decide to use ES6, which you should. Quick example:

console.log(foo); // => Uncaught ReferenceError: foo is not defined
console.log(bar); // => Uncaught ReferenceError: foo is not defined
console.log(foobar); // => undefined

const foo = 'FOO';
let bar = 'BAR';
var foobar = 'FOOBAR';

REFERENCES:

https://developer.mozilla.org/en-US/docs/Glossary/Hoisting

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function

http://stackoverflow.com/questions/31219420/are-variables-declared-with-let-or-const-not-hoisted-in-es6