执行上下文
代码运行周期
我们的代码运行分三个阶段:语法分析、编译阶段、执行阶段
语法分析
先通篇扫描,看看有没有语法错误,有错误就会终止程序执行,比如有中文的 '' ; ''
编译阶段(编译器完成)
主要是编译器将代码翻译为可执行代码,主要有以下步骤:
- 词法分析:将代码字符串分解为词法单元
- 语法分析:生成抽象语法树
- 生成可执行代码:由树结构生成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