Front-end cornerstone: preprocessing mechanism, variable promotion

Get into the habit of writing together! This is the 4th day of my participation in the "Nuggets Daily New Plan·April Update Challenge", click to view the details of the event .

variable promotion

In the "current context", before the code is executed, the browser will first declare and define all keywords with var/function in advance, var will be declared in advance, and function will not only be declared in advance but also defined in advance (assignment).

E.g:

console.log(a);
var a = 1;
console.log(fn);
function fn() {}
复制代码

The declaration and definition of a are after console.log(a), but using a in advance will not report an error but output undefined, indicating that a has been declared in advance .

The declaration and definition of fn are after console.log(fn), but if fn is used in advance, no error will be reported, and fn is correctly output, indicating that fn is not only declared in advance, but also defined (assigned) in advance .

Variable promotion, regardless of whether the condition is true or not, the variable promotion will be performed. However, in the judgment body, the performance of functions in old and new browsers is not the same (var has no effect). In old browsers, function variable promotion is followed by declaration + definition, but in new browsers, function variable promotion only Will declare and not define.

New version browser:

Older version browsers:

Class variable promotion for let and const

Why do let and const promote class variables, because let and const themselves do not have variable promotion, but they have some mechanism to deal with let and const.

Take let as an example:

console.log(a);
let a = 1;
复制代码

Since let does not have a variable promotion mechanism, it will definitely report an error if it is used before it is declared, but what error will it report? "Uncaught ReferenceError: a is not defined" ?

其实不然,报错 「Uncaught ReferenceError: Cannot access 'a' before initialization」

注意:如果你要在浏览器控制台中直接运行,请加上一个块级作用域。

{
    console.log(a);
    let a = 1;
}
复制代码

这是为什么了?其实最开始浏览器从服务器获取的js都是文本(字符串),声明的文件格式「content-type: application/javascript」。浏览器首先按照这个格式去解析代码,也就是进行「词法解析」生成 AST 语法树。

基于 let、const 等声明的变量,在词法解析阶段就已经明确在此上下文中未来一定会存在这些 let、const 声明的变量,在代码执行时,如果在具体声明的变量之前使用了这些变量,浏览器就会报错 「Uncaught ReferenceError: Cannot access 'a' before initialization」。所以说 let 、const 类似会有一种变量提升,但是本质上并不是变量提升。

看如下代码,用 debugger 看看。

debugger;
console.log(a);
var a = 1;
console.log(b);
let b = 2;
复制代码

发现 b 是定义在脚本中,这里的脚本就是 VG(G),而 a 是在 全局 GO 中,说明二者并不是一样的处理,let 词法解析阶段就已经明确在此上下文中未来一定会存在这些 let、const 声明的变量。

接下来我们看一个面试练习。

面试练习

console.log(fn);
function fn() {
  console.log(1);
}
console.log(fn);
var fn = 12;
console.log(fn);
function fn(){
  console.log(2);
}
console.log(fn);
复制代码

第一步变量提升

  1. function fn() {console.log(1);} fn 函数声明加定义,一个函数的创建会在 Heap 堆内存中开辟一块空间(0x001)来存储函数(详情看上一篇文章:函数的底层执行机制),所以 fn -> 0x001。

  1. var fn = 12; var will only declare that it will not be defined, but it is found that fn has been declared in the context, so it will not be repeated.
  2. function fn(){console.log(2);}, fn is now a new function, but it is found that fn already exists in this context, so it will not be repeated, but will be redefined. So open up a new memory space (0x002) to store the new fn function. Compared with the fn memory address in the first step, the opening of new memory is a defined operation, so fn -> 0x002.

Second step code execution

  1. console.log(fn); Look for fn in this context, found to exist, fn -> 0x002. So output ƒ fn(){console.log(2);}
  2. function fn() {console.log(1);} is skipped because this step is already handled in the variable promotion phase.
  3. console.log(fn); Look for fn in this context, found to exist, fn -> 0x002. So output ƒ fn(){console.log(2);}
  4. var fn = 12; The var declaration has already been handled in the variable hoisting phase, now it's time to reassign it. fn -> 12

  1. console.log(fn); Look for fn in this context, found to exist, fn -> 12. So output 12.
  2. function fn(){console.log(2);} is skipped because this step is already handled in the variable promotion phase.
  3. console.log(fn); Look for fn in this context, found to exist, fn -> 12. So output 12.

Summarize

These kinds of questions with variable improvement will often appear in interviews, but many students will think that it is relatively simple and often have problems. Therefore, when encountering such questions, you need to skillfully construct a brain map in your brain to understand the variables in memory. store pointer. In this way, the output results are clear and error-free.

Guess you like

Origin juejin.im/post/7083893296019275784