# Hoisting

## Overview

In this lesson, we'll introduce the concept of hoisting, which deals with how function and variable declarations seem to get 'hoisted' to the top of the current scope. We'll also explain how the problems it causes are easily avoided by following simple rules for where and how declarations should happen within your code.

If you read any pre-ES2015 JavaScript materials, hoisting is sure to come up as a topic of concern. However, follow these two simple rules, and you'll never have to worry about it:

* **Declare all of your functions at the top of their scope**. If the functions are declared in the global scope, simply put them at the top of the JavaScript file. If they're declared inside another function, put the declaration at the top of the function body.
* **Only use `const` and `let`. Never use `var`.**

## Objectives

1. Detail how function and variable declarations are 'hoisted'.
2. Explain why it's best to declare functions and variables (at least those declared with `var`) at the top of the scope.
3. Understand, as always, that ***it's better to use `const` and `let`*** than `var`.

## Function hoisting

[![Let's get hoisting!](https://camo.githubusercontent.com/608fff38c1a00fb2cc24a8e588a9775b27268e6a/68747470733a2f2f637572726963756c756d2d636f6e74656e742e73332e616d617a6f6e6177732e636f6d2f7765622d646576656c6f706d656e742f6a732f7072696e6369706c65732f686f697374696e672d726561646d652f6c6574735f6765745f686f697374696e672e676966)](https://camo.githubusercontent.com/608fff38c1a00fb2cc24a8e588a9775b27268e6a/68747470733a2f2f637572726963756c756d2d636f6e74656e742e73332e616d617a6f6e6177732e636f6d2f7765622d646576656c6f706d656e742f6a732f7072696e6369706c65732f686f697374696e672d726561646d652f6c6574735f6765745f686f697374696e672e676966)

Because the JavaScript engine reads a JavaScript file from top-to-bottom, it would make sense if we had to define a function before we invoked it:

```
function myFunc () {
  return 'Hello, world!';
}

myFunc();
// => "Hello, world!"
```

However, we can invert those two steps and everything works fine:

```
myFunc();

function myFunc () {
  return 'Hello, world!';
}
// => "Hello, world!"
```

***NOTE***: To follow along in your browser's JavaScript console, make sure you type all of the code into the prompt before you press **Enter**. To insert a new line without executing what you've typed, hold **Shift** and press **Enter**. If you type `myFunc();` and then hit **Enter**, the browser will run your code, and you'll see an `Uncaught ReferenceError` telling you that `myFunc is not defined`. If it helps, you can copy and paste the above code all at once, or you can type it on a single line:

```
myFunc(); function myFunc () { return 'Hello, world!'; }
// => "Hello, world!"
```

This reads as though we're invoking the function prior to declaring it, but we're forgetting about the two-phase nature of the JavaScript engine. During the compilation phase, the engine skips right over the invocation and stores the declared function in memory:

```
// The engine ignores all function invocations during the compilation phase.
myFunc();

function myFunc () {
  return 'Hello, world!';
}
```

By the time the JavaScript engine reaches the execution phase, `myFunc()` has already been created in memory. The engine starts over at the top of the code and begins executing it line-by-line:

```
// During the execution phase, the engine invokes myFunc(), which was already initialized during the compilation phase.
myFunc();

// During the execution phase, the engine will simply ignore this function declaration that was already carried out in the compilation phase.
function myFunc () {
  return 'Hello, world!';
}
```

The term for this process is *hoisting* because it feels a bit like your declarations are being hoisted to the top of the current scope. Your declarations **are** being evaluated before the rest of your code gets run, but *hoisting* is a bit of a misnomer: the physical location of the code isn't actually changing at all.

The best way to avoid any confusion brought on by function hoisting is to simply declare your functions at the very top of your code.

## Variable hoisting

We're going to look at some of the hoisting issues caused by `var` because you will encounter this weirdness in legacy code. However, the fix is extremely easy: use `const` and `let` and you'll have no variable hoisting issues.

Look at the following code:

```
function myFunc () {
  console.log(hello);

  var hello = 'World!';
}
// => undefined
```

Given what you know at this point, what do you think will be logged out to the JavaScript console when the code is executed?

```
myFunc();
// LOG: undefined
// => undefined
```

It prints out `undefined`. What the heck?!

You see, in JavaScript, hoisting only applies to variable *declarations*; not variable *assignments*. As a quick refresher on that terminology:

```
// Declaration:
let hello;

// Assignment:
hello = 'World!';

// Declaration and assignment on the same line:
let goodnight = 'Moon';
```

During the compilation phase, the JavaScript engine initializes the variable `hello`, storing it in memory. At this point, however, **no value is assigned to the variable**. As far as the JavaScript engine is concerned, the variable `hello` exists, but it contains `undefined`.

The variable will contain `undefined` until it's assigned a different value during the execution phase. Because of this odd behavior, you'll often see variable hoisting explained by taking some sample code...

```
function myFunc () {
  console.log(hello);

  var hello = 'World!';
}
```

and rearranging it to better indicate the order of events:

```
function myFunc () {
  var hello;

  console.log(hello);

  hello = 'World!';
}
```

When rearranged, it's clear that the variable is initialized as `undefined`, that it still contains `undefined` when it's logged out to the console, and that only after the logging event is it assigned the value of `'World!'`. However, armed with knowledge of what's going on under the hood (the distinct compilation and execution phases), we don't need any of that code transposition nonsense. When we invoke the following function, five things happen:

```
function myFunc () {
  console.log(hello);

  var hello = 'World!';

  return hello;
}

myFunc();
// LOG: undefined
// => "World!"
```

1. The declaration of `hello` (`var hello`) is evaluated during the compilation phase, and the identifier, `hello`, is stored in memory as `undefined`.
2. The execution phase starts, and the JavaScript engine begins stepping through the code, executing each line in turn.
3. At the first line, `console.log(hello);`, the value of `hello` is still `undefined`, and that's exactly what gets logged out to the console.
4. At the second line, the value `'World!'` is assigned to the variable `hello`. From this point on, all references to `hello` in this scope will evaluate to `'World!'`.
5. At the final line, we `return` the value of `hello`, which by now has been assigned and evaluates to `'World!'`.

### Avoiding the confusion of `var` hoisting

[![And I'm not about to hoist myself out of it.](https://camo.githubusercontent.com/6be303c1745b42e1dfda356d6350e4e5be3a50f3/68747470733a2f2f637572726963756c756d2d636f6e74656e742e73332e616d617a6f6e6177732e636f6d2f7765622d646576656c6f706d656e742f6a732f7072696e6369706c65732f686f697374696e672d726561646d652f6e6f745f61626f75745f746f5f686f6973742e676966)](https://camo.githubusercontent.com/6be303c1745b42e1dfda356d6350e4e5be3a50f3/68747470733a2f2f637572726963756c756d2d636f6e74656e742e73332e616d617a6f6e6177732e636f6d2f7765622d646576656c6f706d656e742f6a732f7072696e6369706c65732f686f697374696e672d726561646d652f6e6f745f61626f75745f746f5f686f6973742e676966)

There are two ways to keep the JavaScript engine from 'hoisting' your variables:

1. If, for whatever reason, your current project requires that you use `var`, follow our rule for function declarations and declare everything at the **top** of its scope. E.g., if you need to declare a variable within a function, declare it at the **top** of that function:

   ```
   // BAD
   function myBadFunc () {
     console.log('Just doing some other stuff before we get around to variable declarations.');

     var myVar = 42;
   }

   // GOOD
   function myGoodFunc () {
     var myVar = 42;

     console.log("Much better! The variable declaration is at the top of the scope created by 'myGoodFunc()', so there's no chance it gets 'hoisted'.");
   }
   ```
2. For the love of all things good in this world, ***don't use `var`***. Variables declared with `const` and `let` do technically get 'hoisted', but the JavaScript engine doesn't allow them to be referenced before they've been initialized. Bad:

   ```
   myVar;

   let myVar = "Assignment is optional since we used 'let'.";
   // ERROR: Uncaught ReferenceError: myVar is not defined
   ```

   Good:

   ```
   const myOtherVar = "Gotta assign a value for our beloved 'const'.";

   myOtherVar;
   // => "Gotta assign a value for our beloved 'const'."
   ```

Since we can't even reference them, the whole problem of hoisted variables evaluating to `undefined` prior to assignment is moot.

Hoisting is often cited as an annoyance with JavaScript, but most of those complaints are from a pre-ES2015 world. Rejoice!

## Resources

* [SitePoint — Back to Basics: JavaScript Hoisting](https://www.sitepoint.com/back-to-basics-javascript-hoisting/)
* [MDN — `var` hoisting](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var#var_hoisting)
