Skip to content

Instantly share code, notes, and snippets.

@max-mapper
Last active February 25, 2024 12:24
Show Gist options
  • Save max-mapper/4bed247d9852de93c94c to your computer and use it in GitHub Desktop.
Save max-mapper/4bed247d9852de93c94c to your computer and use it in GitHub Desktop.
JS hoisting by example

JavaScript function hoisting by example

Below are many examples of function hoisting behavior in JavaScript. Ones marked as works successfuly print 'hi!' without errors.

To play around with these examples (recommended) clone them with git and execute them with e.g. node a.js

Notes on hoisting

(I may be using incorrect terms below, please forgive me)

When JS is parsed, a first pass is done over each scope, and function definitions are immediately discovered. An example of a function definition is function foo() {}. When a function is declared like this, with a name, that name becomes available to the entire scope when the code in that scope is executed.

A crude timeline of how JS gets executed:

  1. Parse the scope and detect all function definitions
  2. Execute the code top-to-bottom with all functions found in step 1 available as variables

This behavior is called 'hoisting' because it is almost like the function definitions have been 'hoisted' up to the top of the function.

Assignments are not evaluated until the code is executed. An example of an assignment is var foo = function() {} or var foo = function foo() {}. A function must not be associated with an assignment in order for it to be hoisted (see example L)

Wrapping a function in parenthesis (()) is a quick way to convert a function definition into a function expression, which means it does not get hoisted (similar to assigning the function to a variable). I personally do not use this pattern regularly as I find it overly confusing to newbies etc, but I have included it because it is widely used in e.g. jQuery plugins.

I use hoisting as a code organization tool, for example here I rely on hoisting to make parseStream() available on line 20, even though it is defined on line 41, which I think makes that file more readable as I can put the 'meat' of the function at the top.

// A (works)
function sayHi() {
console.log('hi!')
}
sayHi()
// B (works)
sayHi()
function sayHi() {
console.log('hi!')
}
// C (works)
var sayHi = function() {
console.log('hi!')
}
sayHi()
// D (does not work)
sayHi()
var sayHi = function() {
console.log('hi!')
}
// E (does not work)
(function sayHi() {
console.log('hi!')
})
sayHi()
// F (does not work)
sayHi()
(function sayHi() {
console.log('hi!')
})
// G (works)
(function sayHi() {
console.log('hi!')
})()
// H (works)
(function() {
console.log('hi!')
})()
// I (works)
var sayHi = (function() {
console.log('hi!')
})()
// J (works)
var sayHi = (function() {
console.log('hi!')
})
sayHi()
// K (does not work)
sayHi()
var sayHi = (function() {
console.log('hi!')
})
// L (does not work)
sayHi()
var x = function sayHi() {
console.log('hi!')
}
// M
var x = (function sayHi() {
console.log('hi!')
})
x() // works
sayHi() // does not work
@dengshenkk
Copy link

Thanks for sharing! 🙏🏻

@mrniamster
Copy link

Thanks for sharing

@benjaminyakobi
Copy link

benjaminyakobi commented Sep 2, 2022

Thanks for sharing!
For those who want to explore more about this topic & more, great article to read:
https://www.freecodecamp.org/news/execution-context-how-javascript-works-behind-the-scenes/

@chickenzombie
Copy link

Thank you very much for this theory unit, it was very helpful :)

@YasminOE
Copy link

Thanks for sharing!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment