🔝 Hoisting in JavaScript

August 14, 2019

Table of content:

Hoisting Overview

As we mentioned in the previous article about the lexical scope, JavaScript has some inner process (that we called hoisting) which break block scoping for a variable declared with the var keyword inside blocks. The previous example:

var flag = true
if (flag) {
  var a = 4
  console.log(a) // 4
}
console.log(a) // 4

So why variable a is available besides condition block where the last one was declared, and how hoisting connected to that?

Let’s look at other samples of code:

var flag = true
console.log(a) // undefined
if (flag) {
  var a = 4
  console.log(a) // 4
}

Why does our variable equal undefined instead of getting ReferenceError and message that the a is not defined?

Here hoisting goes. The point is that engine already knows about all variables/function before execution (it catch this info before execution), and it means that your declarations actually are known before when the engine goes to the place where you put them.

So previous example can pe represented like:

var a
var flag = true
console.log(a) // undefined
if (flag) {
  a = 4
  console.log(a) // 4
}

Functions and Hoisting

While variables just moved their declaration at the top of the current scope, functions are completely available from any part of their scope:

foo() // bar

function foo() {
  console.log('bar')
}

But function expressions behave like other variable (their value is undefined until asset):

foo() // TypeError

var foo = function () {
  console.log('bar')
}

With named function expressions situation is the same (they aren’t accessible by name even after assign):

foo() // TypeError: foo is not a function
bar() // ReferenceError: bar is not defined

var foo = function bar () {
  console.log('bar')
}

foo() // bar
bar() // ReferenceError: bar is not defined

Multiple declarations

As we mentioned both variables and function are hoisted. The interesting moment that functions hoisted before variables:

foo() // foo 1

function foo() {
  console.log('foo 1')
}

foo() // foo 1

var foo = function () {
  console.log('foo 2')
}

foo() // foo 2

Any duplicated declarations will overwrite the previous:

foo() // foo 3

function foo() {
  console.log('foo 1')
}

foo() // foo 3

var foo = function () {
  console.log('foo 2')
}

foo() // foo 2

function foo() {
  console.log('foo 3')
}

foo() // foo 2