js执行上下文

js执行上下文

4种情况会创建新的执行上下文

  1. 进入全局代码

  2. 进入function 函数体代码

  3. 进入eval函数参数指定的代码

  4. 进入module代码

全局对象和全局scope

全局声明的变量有两个存储地方,一个是全局对象中,一个是全局scope中。
var和function声明的变量会储存在全局对象中,而let和scope声明的变量会储存在全局的scope中。

var a=1;
function b(){}
let c=1
const d=1

全局对象和全局scope
定义在全局scope中的变量,我们是无法使用window.变量名获取到值的。注意,函数的文本环境只有它自身的scope没有全局对象。

代码执行流程

  1. Step1 创建全局执行上下文,并加入栈顶

  2. Step2 分析

    1. 找到所有的非函数中的var声明
    2. 找到所有的顶级函数声明(不在大括号内的函数声明)
    3. 找到顶级let,const,class声明
    4. 找到块中的声明,函数名不与上述重复
  3. Step3 名字重复

    1. let,const,class声明的名字之间不能重发
      • let声明的变量名不能重复
      • const声明的变量名不能重复
      • let和const声明的变量名不能重复
    2. let,const,class和var,function的名字不能重复
      • let和var、function声明的变量名不能重复
      • const和var、function声明的变量名不能重复
    3. var和function名字重复的,function声明的函数名变量提升优先于var,所以在声明前输出会打印函数,在声明后输出会打印var。
  4. Step4 创建绑定

    1. 找到并初始化var和undefined
    2. 顶级函数声明:找到function名字,并初始化为新创建函数对象
    3. 块级中函数声明:找到名字,初始化为undefined
    4. 找到let,const,class,但未初始化

块中的函数声明

  1. Step2 分析

    1. 找到块中的函数声明
  2. Step3 名字重复

    1. 如果和找到的非函数的var声明、顶级函数声明、顶级let声明、顶级const声明、顶级class声明的名称重复,则不做任何处理。
    2. 如果不重复则在(如果是windown作用域则在全局对象,如果是函数作用域则在函数的scope)上创建一个以函数名为名的变量并初始化为undefined。
  3. Step4

    1. 创建一个块的文本环境,将其连接到原来的文本环境中去。然后执行块中的流程

块中的代码执行流程

块中的代码执行流程和全局的基本一样,就在块中代码执行完后有不同的情况。

  1. Step5 退出块

    1. 如果有函数作用域连接到了块的文本环境,则去全局对象中查看是否有同名的变量,如果有则将块中的变量赋值给全局。如果没有则不做任何处理。
let a=1;
if(true){
  function a(){
    console.log('函数');
  }
}
console.log(a);//1

解释一下函数名和var名冲突

我们在上面说了。

var和function名字重复的,function声明的函数名变量提升优先于var,所以在声明前输出会打印函数,在声明后输出会打印var。

我们看下面的代码:

console.log(a);//f a(){}
var a=1;
function a(){
    console.log(1);
}
console.log(a);//1

因为函数和var重名,函数变量提升优先于var所以第一次输出a返回函数。第二次输出a由于var变量提升在var之后,所以,var在函数之后将函数覆盖,最后输出1。