跳到主要内容

执行上下文

代码运行周期​

我们的代码运行分三个阶段:语法分析、编译阶段、执行阶段

语法分析​

先通篇扫描,看看有没有语法错误,有错误就会终止程序执行,比如有中文的 '' ; ''

编译阶段(编译器完成)​

主要是编译器将代码翻译为可执行代码,主要有以下步骤:

  • 词法分析:将代码字符串分解为词法单元
  • 语法分析:生成抽象语法树
  • 生成可执行代码:由树结构生成js引擎能执行的代码
  • 作用域规则确定:在生成可执行代码的时候,定义作用域的访问规则
  • ..........

执行阶段(js引擎完成)​

  • 执行上下文的创建:作用域链、this、变量对象会被确定
  • 代码执行
  • 执行上下文出栈
  • 垃圾回收
  • .........

由此看见,作用域是在编译阶段生成可执行代码时创建的,执行上下文是在函数进栈,也就是函数执行前一刻创建的,然后会确定作用域链等,之后函数执行

什么是执行上下文​

执行上下文的本质是一块内存,存储着可执行代码执行时需要的环境信息,供代码运行时使用。在 js 中可执行代码包括三个:

  • 全局可执行代码
  • 函数可执行代码
  • eval 可执行代码

所以 js 中执行上下文也包括三种

  • 全局执行上下文
  • 函数执行上下文
  • eval 执行上下文

执行上下文在 ECMA 的标准的不断迭代中也一直发生着变化,简单列举下

es3 时的执行上下文:​

  • 变量对象(Variable Object,VO):用于存放变量、函数声明和 arguments
  • 作用域链(Scope Chain):变量在上下文的访问规则
  • this:函数执行的 this 指向

在 ES3 中作用域链,其实就是变量对象的集合

执行上下文的生命周期​

  • 创建:
    • 创建VO ( Variable Object ) 变量对象,此时VO不能被访问
    • 创建变量对象
      • 创建arguments对象,将函数的形参名称和值同步到VO。
      • 扫描上下文的变量声明:
        • 1、将变量作为VO的一个属性存储,值为undefined
        • 2、如果变量的名字已经在变量对象里存在,将不会进行任何操作并继续扫描
      • 扫描上下文的函数声明(而非函数表达式):
        • 1、在VO创建一个属性名为当前扫描的函数名,值为函数体
        • 2、如果函数的名字已存在,则重新赋值当前函数的函数体。
    • 创建作用域链
    • 确定this指向
  • 运行:
    • VO激活变为AO(Active Object),代码执行,变量的值可在当前AO对象里查询,也可在作用域链中查询。代码执行完后出栈
  • 销毁:垃圾回收

一个例子​

fun 的执行周期

function fun(a) {
console.log(a);
var a = 123;
console.log(a);
function a() {};
console.log(a);
var b = function() {};
console.log(b);
function d() {};
}
fun(1);
/* VO的创建过程 ----------------------------------------------------------
(1)创建空的VO对象
VO { }
(2)
VO {
a: undefined,
b: undefined
}
(3)
VO {
a: 1,
b: undefined
}
(4)
VO {
a: function a() {},
b: undefined,
d: function d() {}
}
*/

/*函数执行过程 VO --> AO -----------------------------------------------------------------
|2 console.log(a); //function a() {}

---var a = 123; ==> AO的创建时 a 已经声明提升过,所以该步是给a赋值,不会执行变量声明过程
AO {
a: 123,
b: undefined,
d: function d() {}
}
|5 console.log(a); // 123

---函数体部分已被声明提升了,所以执行过程中会被略过

|8 console.log(a); // 123

---给 b 赋予函数体
AO {
a: 123,
b: function b() {},
d: function d() {}
}

|11 console.log(b); // function b() {}
*/

// 出栈,等待销毁 --------------------------------------------------------------

es6 之后的执行上下文:​

  • 词法环境:
  • 变量环境
  • this value

包含的环境信息​

  • 变量对象:存储着变量声明、函数声明和 arguments
  • 作用域链:变量在上下文的访问规则
  • this:函数执行的 this 指向

es5