作用域

js的作用域有两种,全局作用域局部作用域,对于 var 声明的变量,只有 function才可以为他创建局部作用域,对于let 声明的变量,支持块级作用域 { } 生成

变量提升

什么是变量提升?

在编译过程,将所有变量声明和函数声明提升到作用域顶部
JavaScript的源代码在运行的时候,会经过两个阶段:编译和执行。而且,编译阶段往往就在执行阶段的前几微秒甚至更短的时间内。
在编译的过程,会经历词法分析,语法分析,生成中间代码等过程,变量提升发生在编译阶段,生成可执行的中间代码。

提升原理

LHS查询

在编译的过程中,先将标识符和函数声明给提升到其对应的作用域的顶端。标识符解析的时候,会进行LHS查询,在LHS查询的时候,如果标识符一直找不到声明的位置,那么最终就会在全局环境生成一个全局变量。 LHS : 指的是赋值操作的左端。

提升案例

补齐声明

在解析过程中,如果找不到声明,最终在全局环境生成一个全局变量

  1. function test(){
  2. message = 'hi'
  3. }
  4. test()
  5. console.log(message)

还原编译后代码

  1. var message
  2. function test(){
  3. message = 'hi'
  4. }
  5. test() //message = 'hi'
  6. console.log(message)
  7. 执行
  8. hi

函数只提升声明式

函数提升,只会提升声明式函数,而不会提升函数表达式

  1. f();
  2. fn();//fn is not a function
  3. //函数表达式
  4. var fn = function(){
  5. console.log(1)
  6. }
  7. //函数声明
  8. function f(){
  9. console.log(0)
  10. }

编译结果

  1. //函数声明
  2. function f(){
  3. console.log(0)
  4. }
  5. var fn = undefined;
  6. f();
  7. fn();
  8. fn = function(){
  9. console.log(1)
  10. }

所以执行会报错

  1. 0
  2. Uncaught TypeError: fn is not a function
  3. at <anonymous>:2:1

再看下这个例子

  1. function test() {
  2. function f3(a) {
  3. f = a;
  4. console.log("1");
  5. };
  6. }
  7. console.log(typeof f3); // undefined

所以函数提升只会提升到作用域顶部

重复声明优先 function

同名声明function会覆盖var声明的

  1. add();
  2. console.log(typeof add);
  3. function add(){
  4. console.log('加++');
  5. }
  6. var add;

编译

  1. var add;
  2. function add(){
  3. console.log('加++');
  4. }
  5. add();
  6. console.log(typeof add);

image.png