Scope, hoisting, event loop: Hoisting

Normally you know that you can only reference a variable or call a function after it’s been defined.

It’s normal to think like that, too. First you define something, then you use it.

But JavaScript before executing your code might reorder it according to some rules, and if you’re not careful you might be surprised.

Let’s see.

We have 2 special cases:

  • variables defined with var
  • functions declared with the traditional function syntax

For variables, we can initialize a variable before declaring it:

test = 'hello'
var test

console.log(test) //'hello'

And for functions, we can call the function before declaring it:

bark() //'woof!'

function bark() {
  console.log('woof!')
}

Sounds like crazy, right? We can call the function before declaring it? And also set the variable value!

This happens because JavaScript before executing the code actually moves all var variable declarations, and traditional function declarations, on top.

This is called hoisting.

To avoid confusion, I always recommend to declare var variables at the beginning of a function.

Or to not use var at all, because let and const declarations do not suffer from this.

If you try changing var test to let test, you’ll get an error

ReferenceError: Cannot access 'test' before initialization

The same goes if you use an arrow function or also a function expression:

bark()

var bark = function() {
  console.log('woof!')
}

In this case you’ll see an error

TypeError: bark is not a function

Lessons in this unit:

0: Introduction
1: Global scope
2: Function scope
3: Block scope
4: Shadowing
5: ▶︎ Hoisting
6: Closures
7: An issue with `var` variables and loops
8: The event loop