Hoist ’em up!

Hoisting and Execution Context in Javascript

Dana Jackson
3 min readJan 25, 2021

Javascript is unique among most other programming languages in its use of hoisting — bringing certain elements of code to the top. In this blog post I will define hoisting, and discuss how it is achieved.

Hoisting

When a Javascript program is run, functions and variables are effectively brought to the top of the script so that they are available at any point in the code. This reordering is referred to as hoisting. Nothing in the code actually changes, but it allows for the hoisted elements to be accessible even before they are called.

Functions are hoisted first

Function declarations are hoisted to the top of the global execution context (the global scope of the entire program), along with their function bodies. This allows the logic contained in a function to be available anywhere in the global context. It is important to note that while function declarations are hoisted, function expressions and arrow functions are not.

Below is an illustration of a function declaration being hoisted in Javascript. We call the function on the first line, and it returns the desired output even though it isn’t defined until after it’s called.

console.log(sayHello)function sayHello(){
console.log("Hi there!")
}
//==> Hi there!

Variables are hoisted next

When variables that are set with the special word “var” are hoisted something a bit funnier happens. Space in the the computer’s memory is reserved for a variable that is declared, but the definition of the variable is not hoisted along with it. This means that a variable will return “undefined” if it is called before it is defined. Don’t get this confused with “not defined”, which means that the variable doesn’t exist at all in the code.

With the release of ES6 in 2015, Javascript gave us the additional special words “let” and “const”, which get yet another slightly different treatment upon hoisting. They are also assigned memory space, but are uninitialized. Using “let” or “const” will return an error instead of “undefined” if they are called before being defined.

console.log(word)var word = "monkey"//==> undefined--------------------------------------------------------------------
console.log(word)
let word = "monkey"//==> Uncaught ReferenceError: word is not defined

Javascript Execution Context

Hoisting is made possible by Javascript’s two-phased execution context. Defining the execution context is a bit like defining “the universe”. It’s where everything happens. A Javascript engine runs code in two distinct phases, the creation phase and the execution phase. Hoisting happens because functions and variables are stored during the creation phase, making them available at any place in the code, within their scope of course, during the execution phase.

Creation Phase

During the creation phase the Javascript engine reads over all of the code, and when it gets to a function or variable it carves out some space in memory to store it so the function or variable is available during the execution phase. It also creates a global object, the window in a web browser for example, which is the context for the program’s Javascript code.

Execution Phase

During the execution phase the Javascript engine executes code line by line. It defines variable that were declared and stored in the creation phase, and it runs functions that have been called.

Scope

As we discuss the order of events and who has access to what as code is run, it’s worth a quick mention of scope. Regardless of hoisting, “let” and “const” variables are block scoped, which means they are only available within the context of the code block where they are declared, in other words within their curly braces. “Var” variables are function scoped, available anywhere inside the function where they are declared. It is generally good practice to not use “var” unless you need to. Stick to “let” and “const”.

In the first example below, I defined “greeting” with the “let” special word inside the inner-most curly braces, so when I try to access it from one level up I get “undefined”. In the second example I use “var” so “greeting” is available anywhere within its encompassing function.

function sayHello(){
if (1 > 0){
let greeting = "hi"
}
return greeting
}
console.log(sayHello())//==> undefined
--------------------------------------------------------------------
function sayHello(){
if (1 > 0){
var greeting = "hi"
}
return greeting
}
console.log(sayHello())//==> hi

Enjoy Javascript’s hoisting and scoping! Is it just me or does it sound like we’re on a pirate ship?

--

--

Dana Jackson

Hi! I am a bassoonist and a software engineer, a mash-up of the obscure and the mainstream, and I’m based in Seattle.