One of the oddities of JavaScript is that you can use variables and functions before they are declared. It is as if variable declarations and function declarations were promoted to the top of the code.

sayHi() // Hi there!

function sayHi() {
    console.log('Hi there! ')
}

name = 'John Doe'
console.log(name)   // John Doe
var name
Copy the code

However, JavaScript does not move your code, so “variable lifting” in JavaScript is not really “lifting”.

JavaScript is a single-threaded language, so execution must be sequential. But instead of analyzing and executing line by line, it’s analyzing and executing section by section, with the compile phase first and then the execution phase.

During the compile phase, milliseconds before the code actually executes, all of the variable and function declarations are detected and added to memory within a JavaScript data structure called the Lexical Environment. So these variables and functions can be used before they are actually declared.

Function increase

sayHi() // Hi there!

function sayHi() {
    console.log('Hi there! ')}Copy the code

Because function declarations are added to the Lexical Environment at compile time, when the JavaScript engine encounters the sayHi() function, it finds the function from the Lexical Environment and executes it.

lexicalEnvironment = {
  sayHi: < func >
}
Copy the code

Var variable promotion

console.log(name)   // 'undefined'
var name = 'John Doe'
console.log(name)   // John Doe
Copy the code

The above code is actually divided into two parts:

  • var nameRepresentation declaration variablename
  • = 'John Doe'Is a variablenameAssign the value ‘John Doe’.
var name    // Declare variables
name = 'John Doe' // Assign
Copy the code

Only var name is promoted; assignment is not promoted, but why is name undefined?

The reason for this is that when JavaScript finds the variable declared by the var keyword at compile time, it is added to the lexical environment, initializes a value called undefined, and later assigns the value to this variable when executing the code into the assignment statement.

// Compile phase
lexicalEnvironment = {
  name: undefined
}

// Execution phase
lexicalEnvironment = {
  name: 'John Doe'
}
Copy the code

So function expressions are not “promoted” either. HelloWorld is a variable whose default value is undefined, not function.

helloWorld();  // TypeError: helloWorld is not a function

var helloWorld = function(){
  console.log('Hello World! ');
}
Copy the code

Let & const raise

console.log(a)  // ReferenceError: a is not defined
let a = 3
Copy the code

Why is a ReferenceError reported? Are variables declared let and const not “promoted”?

Virtually all declarations (function, var, let, const, class) are “promoted”. However, only variables declared with the var keyword are initialized with undefined. Variables declared with let and const are not initialized.

They are initialized only when the JavaScript engine encounters their lexical binding (assignment) during execution. This means that the variable cannot be accessed until the JavaScript engine declares it. This is what we call the Temporal Dead Zone, the time span between variable creation and initialization, and they are not accessible.

If the JavaScript engine cannot find a value for let and const where they are declared, it will either assign undefined or return an error (in the case of const).

For example:

let a
console.log(a)  // undefined
a = 5
Copy the code

During compilation, the JavaScript engine encounters the variable a and stores it in the lexical environment, but because it is declared with the let keyword, the JavaScript engine does not initialize the value for it, so at this point in compilation, the lexical environment looks like this:

lexicalEnvironment = {
  a: <uninitialized>
}
Copy the code

If we want to use a variable before it is declared, the JavaScript engine will get the value of the variable from the lexical environment, but the variable is still in the uninitialized state, so it will return a ReferenceError.

In the execution phase, when the JavaScript engine executes the variable declaration, if the variable is declared and assigned, the value in the lexical environment will be updated. If the variable is declared but not assigned, then the JavaScript engine will assign undefined to the variable.

Tips: We can use them before the let and const declarations, as long as the code is not executed before the variable declaration:

function foo() {
    console.log(name)
}

let name = 'John Doe'

foo()   // 'John Doe'
Copy the code

The Class promotion

Just like let and const, classes are “promoted” in JavaScript, and are not initialized until they are actually assigned, and are also affected by the Temporal Dead Zone.

let peter = new Person('Peter'.25) // ReferenceError: Person is not defined

class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age; }}let John = new Person('John'.25); 
console.log(John) // Person { name: 'John', age: 25 }
Copy the code