Let’s talk about JavaScript’s hoisting and scope concepts…

Erica Ann Basak
5 min readFeb 21, 2020

Anyone else here a bit confused? By the end of this article, any confusion there may be around these two concepts should be clarified. They definitely made me scratch my head countless times. Let’s dive in…

Hoisting…

JavaScript’s hoisting is the behavior in which variables and function declarations are “hoisted” or raised up to the top of your code. Let’s break this down further — they are parsed and evaluated before any other code. Keep in mind that a JavaScript file is read from top-to-bottom. It makes most sense to write a function declaration before it is invoked. However, in JavaScript it can go either way — a function declaration can be written before it is invoked or vice versa, a function can be invoked before the function has been declared.

Defined function and then invoking it afterwards

JavaScript is able to place the invocation before the function declaration because of execution context. The JavaScript engine skips over the invocation and stores the declared function in memory in the creation phase. More on that below.

Invoked the function prior to declaring it

Execution Context is the abstract concept of the ‘environment’ where the function is executed in. Every piece of JS code is ran in an execution context. The execution context is created in two phases: 1) creation phase and 2) execution phase. By the time the engine is in the execution phase, the engine invokes the the function, which was already initialized during the creation phase. During the execution phase, the engine will bypass the function declaration that was already carried out in the creation phase. Function declarations are being evaluated before the rest of the code gets run.

Variable hoisting…

Prior to ECMAScript 6, the legacy code used the keyword var. Now, the preferred keywords are let and const. With let and const, there are no variable hoisting issues. Let’s take a look at a few examples below.

Notice that it prints out undefined! Why? Because JavaScript’s hoisting only applies to variable declarations and not variable assignments. Only declarations are hoisted. Here is a quick refresher of declaration and assignment.

In the above example, in the creation phase, the variable name is initialized and stored in memory. No value is assigned to the variable. The engine recognizes that the name variable exists, but it is undefined. It will remain undefined until it is assigned a different value in the execution phase.

Take a look at the three examples below. They are the same function — but each one uses a different keyword of either var, let, and const. As you’ll notice, the myFunc function uses the var keyword and there is variable hoisting — not desirable. Referencing a variable prior to it’s initialization results in undefined. The next is the myFunc1 function, which uses the keyword let. There is an Uncaught ReferenceError: cannot access ‘hello’ before initialization. The same goes for the final example, function myFunc2. By using const, we encounter the same Uncaught ReferenceError as we did with the keyword let.

Variable hoisting with the keyword var
No variable hoisting with the keyword let
No variable hoisting with the keyword const

The below chart should help solidify the above concepts.

Scope…

JavaScript’s scope is literally the scope in which a variable can be accessed. There are two types of scope, 1) local scope and 2) global scope. A local variable is declared inside the function. A global variable is declared outside the function. Each function creates it’s own scope. Var keyword restricts a variable to local scope. When no keyword(var, let, const) is used, then the variable is considered to be in the global scope, not usually desirable.

A block scope statement also creates it’s own scope. The block scope is the code written between the curly braces {}.

In the example below, the variable someNum is not block scoped because of the keyword var.

Keyword var is NOT block scoped

In the example below, the variables otherNum and anotherNum are used with the keywords const and let, which are block scoped.

Keyword let and const are block scoped

In the below example, we have a function expression that takes in two parameters all saved to a variable called greeting. This greeting function lives in global scope and it is in the top most level in this program AKA the parent function. The variable salutation is confined to the local scope of the greeting function. Parent scopes cannot access information in their children scopes. Thus you can see when salutation is called there is a ReferenceError: salutation is not defined. The code with in the code block is it’s own local scope, therefore, you cannot make reference to variables found within that code block. Take a look at the example below:

Global scope is when keywords such as var, let, and const are not declared with a variable. If this happens, you’ll most likely run into errors. Note, that regardless of where the created variable without a keyword is in your code, it is considered globally scoped. See the example below.

Lastly, an important note about scope is that JavaScript will refer to the nearest-in-scope variable. In scope variables have precedence over out-of-scope variables with the same label.

In Summary…

Best practice is to declare functions at the very top of your code. Do this by writing the function declaration followed by the invocation. All variable names including function expressions are hoisted to the top of the code and given values of undefined. Using let or const instead of var can remove the unexpected results of undefined in your code. Every function creates it’s own scope.

Hopefully, your feeling better about these two concepts and you can see both these concepts go hand-in-hand.

Happy coding…

--

--