Understanding JavaScript hoisting

Have you ever wondered about the origin of the bizarre magic that allows JavaScript programmers to use variables and functions before they are declared?

It’s called “hoisting” and it’s the process of lifting all variable declarations using var – remember, only using var – to the top of their scope when JavaScript is compiled.

And it’s not over: once all var variabile declarations have been hoisted, it’s time to hoist functions declarations, which move to the very top of their scope, even above variables.

Ok, stop the train, I want to get off, you are not saying JavaScript is compiled, are you? Everybody knows JavaScript is an interpreted language, not a compiled language.

Well, sort of. When JavaScript code is executed, the interpreter is capable of looking for all var variable declarations and all functions declarations and bring them somehow at the top of their scope.

Basically we can say the interpreter runs twice: the first time adjusting a bit your script, if needed, and the second time actually executing it line by line as we all expect from an interpreted language.

Your script, I mean your actual script in your text editor, does not change, it’s just that JavaScript interpreter performs hoisting somewhere under the hood, so in the end we can say the interpreter is working on some kind of rearranged – or compiled – script.

Let’s have a look at a couple of examples.

If you execute this simple script:

console.log(a);

The result will be:

Uncaught ReferenceError: a is not defined

This happens because a variable has never been defined.

Now let’s try with:

console.log(a);
var a = 10;

As you can see, we try to log a variable before it’s declared, so we should get the same error, but actually we get:

undefined

Why? Because of hoisting. This is the compiled script ran by the interpreter:

var a;
console.log(a);
a = 10;

Now, that undefined output makes much more sense.

Now let’s make things more difficult:

b();

We are trying to execute a function which is not declared, so we get

Uncaught ReferenceError: b is not defined

Thanks to hoisting, we can fix the script this way:

b();
function b() {}

And this will work, although the function has been declared after we call it. And this is where troubles start:

var c = b();
function b() {
    a = 100;
    return (a / 2);
}
console.log(c);
console.log(a);

We are expecting c to be 50, and a to fire a reference error because we never declared it outside the scope of b. But…

50
100

That’s because if you assign an undeclared variable, that is if you omit the var keyword, JavaScript automatically assigns it to the global scope.

There is another interesting case to cover:

var a = 100;
b();
function b() {
    console.log(a)
    var a = 200;
    console.log(a);
}

Here you might expect the output at line 4 to be 100, just like you declared it at line 1, but we get

undefined
200

Because the declaration of local a variable at line 5 hoists in its inner scope inside the function.

Also keep in mind hoisting occurs only to function declarations, and not to function expressions:

b();
c();
function b() {};
var a = function c() {};

Throws

Uncaught ReferenceError: c is not defined

As you can see, hoisting can cause some headache, so here are my two advices not to run in trouble with it:

1 – Remember to declare your variables at the very top of your script. This will make it look like the script the machine is going to interpret.

2 – Always declare variables, not just using var, but above all using const and let, which do not allow hoisting.

Happy coding.

Get the most popular Phaser 3 book

Through 202 pages, 32 source code examples and an Android Studio project you will learn how to build cross platform HTML5 games and create a complete game along the way.

Get the book

215 GAME PROTOTYPES EXPLAINED WITH SOURCE CODE
// 1+2=3
// 100 rounds
// 10000000
// 2 Cars
// 2048
// A Blocky Christmas
// A Jumping Block
// A Life of Logic
// Angry Birds
// Angry Birds Space
// Artillery
// Astro-PANIC!
// Avoider
// Back to Square One
// Ball Game
// Ball vs Ball
// Ball: Revamped
// Balloon Invasion
// BallPusher
// Ballz
// Bar Balance
// Bejeweled
// Biggification
// Block it
// Blockage
// Bloons
// Boids
// Bombuzal
// Boom Dots
// Bouncing Ball
// Bouncing Ball 2
// Bouncy Light
// BoxHead
// Breakout
// Bricks
// Bubble Chaos
// Bubbles 2
// Card Game
// Castle Ramble
// Chronotron
// Circle Chain
// Circle Path
// Circle Race
// Circular endless runner
// Cirplosion
// CLOCKS - The Game
// Color Hit
// Color Jump
// ColorFill
// Columns
// Concentration
// Crossy Road
// Crush the Castle
// Cube Jump
// CubesOut
// Dash N Blast
// Dashy Panda
// Deflection
// Diamond Digger Saga
// Don't touch the spikes
// Dots
// Down The Mountain
// Drag and Match
// Draw Game
// Drop Wizard
// DROP'd
// Dudeski
// Dungeon Raid
// Educational Game
// Elasticity
// Endless Runner
// Erase Box
// Eskiv
// Farm Heroes Saga
// Filler
// Flappy Bird
// Fling
// Flipping Legend
// Floaty Light
// Fuse Ballz
// GearTaker
// Gem Sweeper
// Globe
// Goat Rider
// Gold Miner
// Grindstone
// GuessNext
// Helicopter
// Hero Emblems
// Hero Slide
// Hexagonal Tiles
// HookPod
// Hop Hop Hop Underwater
// Horizontal Endless Runner
// Hundreds
// Hungry Hero
// Hurry it's Christmas
// InkTd
// Iromeku
// Jet Set Willy
// Jigsaw Game
// Knife Hit
// Knightfall
// Legends of Runeterra
// Lep's World
// Line Rider
// Lumines
// Magick
// MagOrMin
// Mass Attack
// Math Game
// Maze
// Meeblings
// Memdot
// Metro Siberia Underground
// Mike Dangers
// Mikey Hooks
// Nano War
// Nodes
// o:anquan
// One Button Game
// One Tap RPG
// Ononmin
// Pacco
// Perfect Square!
// Perfectionism
// Phyballs
// Pixel Purge
// PixelField
// Planet Revenge
// Plants Vs Zombies
// Platform
// Platform game
// Plus+Plus
// Pocket Snap
// Poker
// Pool
// Pop the Lock
// Pop to Save
// Poux
// Pudi
// Pumpkin Story
// Puppet Bird
// Pyramids of Ra
// qomp
// Quick Switch
// Racing
// Radical
// Rebuild Chile
// Renju
// Rise Above
// Risky Road
// Roguelike
// Roly Poly
// Run Around
// Rush Hour
// SameGame
// SamePhysics
// Save the Totem
// Security
// Serious Scramblers
// Shrink it
// Sling
// Slingy
// Snowflakes
// Sokoban
// Space Checkers
// Space is Key
// Spellfall
// Spinny Gun
// Splitter
// Spring Ninja
// Sproing
// Stabilize!
// Stack
// Stairs
// Stick Hero
// String Avoider
// Stringy
// Sudoku
// Super Mario Bros
// Surfingers
// Survival Horror
// Talesworth Adventure
// Tetris
// The Impossible Line
// The Moops - Combos of Joy
// The Next Arrow
// Threes
// Tic Tac Toe
// Timberman
// Tiny Wings
// Tipsy Tower
// Toony
// Totem Destroyer
// Tower Defense
// Trick Shot
// Tunnelball
// Turn
// Turnellio
// TwinSpin
// vvvvvv
// Warp Shift
// Way of an Idea
// Whack a Creep
// Wheel of Fortune
// Where's my Water
// Wish Upon a Star
// Word Game
// Wordle
// Worms
// Yanga
// Yeah Bunny
// Zhed
// zNumbers