Kula.blog

Learn JS. Hoisting (1)

It's common to hear warnings about hoisting in JavaScript. How unexpected it is that your variables or functions are moved somehow before your code is interpreted. First, it's not true. Second, what's going on is pretty useful. Let's start from the ground up to make it easier to understand.

Is hoisting real?

console.log(a); // undefined

a = 42;

console.log(a); // 42

var a;

Did we use a before it was declared? Why does it exist? What does this weird undefined even mean? How were we able to assign a value of 42 before it was declared?!

How it works

The first thing to understand is that JS code goes through two stages:

  1. Compilation (Lexing, parsing, optimizations and code generation)
  2. Execution.

It makes sense to think about lexing as a first step of the compilation. It collects all function declarations and var variable declarations and adds their names to the scope.

Lexical Environment

Given code like:

var a = 42;
function meaning(){
return a;
}

It goes through the lexing that results in Lexical Environment similar to:

// Lexical Environment 
{,
meaning: < function >,
a: undefined
}

What does undefined even mean?

undefined means that variable has it's name in the lexical scope, but it's value is not defined yet. That's the reason you can use the variable before it was declared. Its name was already in the Lexical Scope.

What about functions?

< function > - is a text I've picked for the code of your function. Functions start ready and executable in the whole scope.

console.log(meaning()); // 42

function meaning(){
return 42;
}

Thanks to that you can use functions at the top of the file. It can be instrumental in the day to day job. You can put all logic at the top of the file - that's what you see first when you open one and hide all the implementation details in functions down below.

What happens to the variables during execution?

console.log(a); // undefined

a = 42;

console.log(a); // 42

var a;

Let's add Lexical Environment to the comments:

// Lexical Environment: { a: undefined }

console.log(a); // undefined

a = 42;
// Lexical Environment: { a: 42 }

console.log(a); // 42

var a;
// No changes to Lexical Environment: { a: 42 }

The var a starts with the value of undefined but gets the value of 42 in the line a = 42; during execution.

Summary

Variable and function declarations are added to Lexical Environment before your code is executed. For that reason, their names are available before the declarations.

It's a little more complicated for const and let, but that has to wait for the next post: Learn JS. Hoisting (2). Temporal Dead Zone.


← Home