What is variable promotion

In the process of JavaScript code execution, the JavaScript engine promotes the declaration part of variables and functions to the beginning of the code, which is called variable promotion

When a variable is promoted, it is given the default value undefined

The declaration part of a variable is improved:

console.log(a) // undefined

var a = 1
Copy the code

The declaration part of the function is improved:

console.log(add(1.2)) / / 3

function add(x, y) {
  return x + y
}
Copy the code

Second, the principle of variable promotion

Variable promotion = physical movement?

No, the location of variable and function declarations in code does not change; they are put into memory by the JavaScript engine at compile time

A piece of code, when compiled, generates two parts:

  • Execution context: The context in which JavaScript executes a piece of code
    • The variable environment
    • Lexical environment
  • Executable code

Compile first, then execute:

  • Compile phase: declarations of variables and functions are stored inThe variable environmentIn, the default value of the variable is set toundefined
  • Execution phase: The JavaScript engine looks for custom variables and functions from the variable environment
console.log(a)

console.log(add(1.2))

var a = 1

function add(x, y) {
  return x + y
}
Copy the code

The compiled:

// The variable environment of the execution context

a = undefined

add = address1 -> function (x, y) { return x + y }
Copy the code
// Executable code

console.log(a) // undefined

console.log(add(1.2)) / / 3

a = 1
Copy the code

3. Defects of variable promotion

As a result, a lot of code is counterintuitive

1. Variables are easy to be overwritten without being noticed

function fn() {
  var a = 1

  if (true) {
    var a = 2
    console.log(a)
  }

  console.log(a)
}

fn()
Copy the code

The compiled:

// fn's execution context variable environment

a = undefined
Copy the code
// Fn's executable code

a = 1

if (true) {
  a = 2
  console.log(a) / / 2
}

console.log(a) / / 2
Copy the code

2. Variables that should have been destroyed were not destroyed

function fn() {
  for (var i = 0; i < 5; i++) {
    console.log(i)
  }

  console.log(i)
}

fn()
Copy the code

The compiled:

// fn's execution context variable environment

i = undefined
Copy the code
// Fn's executable code

for (i = 0; i < 5; i++) {
  console.log(i) // 0 1 2 3 4
}

console.log(i) / / 5
Copy the code

Iv. How does ES6 solve the problems caused by variable promotion

Scope: The accessible scope of variables and functions

ES6 before:

  • Global scope
  • Function scope

After the ES6:

  • Block-level scope{}

ES6 implements block-level scope by using the let or const keyword

function fn() {
  var a = 1
  let b = 2

  {
    let b = 3
    var c = 4
    let d = 5

    console.log(a)
    console.log(b)
  }

  console.log(b)
  console.log(c)
  console.log(d)
}

fn()
Copy the code

Step 1: Compile and create the execution context

Inside the function:

  • throughvarAll declared variables are stored at compile time inThe variable environmentIn the
  • throughletAll declared variables are stored at compile time inLexical environmentIn the
  • Inside the scope block, throughletDeclared variableIt’s not stored in a lexical environmentIn the
// Fn's execution context

// Variable environment
a = undefined
c = undefined

// lexical context
b = undefined
Copy the code

Step 2: Continue executing the code

When entering a scoped block, variables declared by let are stored in a separate area of the lexical environment that does not affect variables outside the scoped block

Inside the lexical environment, a small stack structure is maintained:

  • The bottom of the stack is the outermost variable of the function
  • Entering a scoped block pushes variables inside that scoped block to the top of the stack
  • When the scope execution is complete, the information for that scope is popped from the top of the stack

Implement ing…

// Fn's executable code

a = 1
b = 2
Copy the code
// Fn's execution context

// Variable environment
a = 1
c = undefined

// lexical context
b = 2
Copy the code

Implement ing…

// Fn's executable code

{
  // Enter the scope block
}
Copy the code
// Fn's execution context

// Variable environment
a = 1
c = undefined

// lexical context
---
b = undefined
d = undefined
---
b = 2
Copy the code

Implement ing…

// Fn's executable code

{
  b = 3
  c = 4
  d = 5
}
Copy the code
// Fn's execution context

// Variable environment
a = 1
c = 4

// lexical context
---
b = 3
d = 5
---
b = 2
Copy the code

Implement ing…

// Fn's executable code

{
  // Search down the stack of the lexical environment. If it is found in a block in the lexical environment, it is returned directly to the JavaScript engine. If it is not found, it continues to look in the variable environment
  console.log(a) / / 1
  console.log(b) / / 3
}

console.log(b) / / 2
console.log(c) / / 4
console.log(d) // Uncaught ReferenceError: d is not defined
Copy the code

Five, the summary

  • ES6 introduced block-level scoped keywords due to design flaws such as variable overwriting and variable contamination in JavaScript variable promotionletconstTo solve these problems
  • Variable promotion is implemented through the variable environment, and block-level scope is implemented through the stack structure of the lexical environment