Hoisting is the behavior of moving declarations to the top of the current scope. This is the default behavior in JavaScript when using the var keyword but using the new let and const keywords means this does not occur.
Hoisting in Action.
Here we can see that the variable is declared after it's been used, so how does this still work?
How and Why?
Why does JavaScript do this? Hoisting is done during the interpreter's first run through the code. The JavaScript engine was designed in such a way that your code is run twice, the first time it runs through some syntax checking and anything that uses the global object methods. It then does some optimisation to improve performance, which is where hoisting comes in. The second pass is where your code gets run.
Hoisting will move all declarations to the top of the current scope (top of the current file or function).
Initializations are Not Hoisted.
In this example, you can see that when declaring and initialising a variable in the same line the javascript engine does not optimise this block. As such you get an undefined error when trying to access the variable.
Let and Const behave differently
When changing the first example to use the let or const keywords instead of var everything goes belly up. If you open your console window you will spot the JavaScript engine throwing exceptions (I've added images if you can't be bothered 😉 )
You can see nothing is present in the results pane, that's because these new keywords behave differently. The errors below are easy enough to understand, a const needs to be initialised when declared, whereas a let gets checked during the first cycle of the interpreter.
Put your declarations in scope.
Hoisting is pretty cool eh? It's great that JavaScript is so forgiving and allows things like this to work. Equally, it can mean that code works when you're not expecting it to. Going forward, it's probably best to keep all your declarations at the beginning of every scope though! With the introduction and mass adoption of the let and const keywords, it's important to know the differences, and know that simply changing all your vars to lets can cause problems in your application.
What about Functions
Hoisting also applies to function declarations, which is why you can define your function after you call them! However, Function expressions/Anonymous methods do not get hoisted in a similar fashion to let and const. Take a look at this last CodePen, we can see that the variable declarations get hoisted from the bottom, but the anonymous function call does not, which kills the engine throwing errors.
Finally, it's good to know that functions get hoisted before variables! So when refactoring legacy code, remember to look at the scope of all your variables and think about how the interpreter will be parsing the code you are modifying.
The main reason for this is because let and const are block scoped. var on the other hand is not and therefore can be hoisted up to the global context (as long as 'use strict' is not present
James - https://dev.to/jamesthomson
Top comments (3)
Interesting that "let" and "const" did not inherit the hoisting behavior. I've come to understand that "var" should not be used going forward as of ES6 in favor of let and const... was this a deliberate decision to remove the hoisting behavior from Javascript altogether in time?
The main reason for this is because
let
andconst
are block scoped.var
on the other hand is not and therefore can be hoisted up to the global context (as long as'use strict'
is not present).Indeed, thanks for the added clarification James. I'll add that in. I'll blockquote you! 😊