什么是执行上下文?
执行上下文是以后 JavaScript 代码被解析和执行时所在环境的抽象概念。
执行上下文的意义在于,它给出一个形象模型,能够更简略得理解 js 的运行机制。同时,执行上下文对了解 js 内存,闭包,垃圾回收等具备粗浅意义,它能够让咱们在不是很理解底层代码的状况上来剖析内存和执行过程。
执行上下文能够被分为三类:
- 全局执行上下文:只有一个,在客户端由浏览器创立,个别为 window;
- 函数执行上下文:能够有无数个,只有在函数调用时才会被创立,每次调用函数都会创立一个新的执行上下文;
- eval 执行上下文:指的是在 eval 中的代码,个别不举荐应用。
这么多执行上下文,能够应用执行栈来进行治理。
执行栈
执行栈,也叫调用栈,它是一个 LIFO 的构造,用于贮存代码在执行期间所须要的上下文。
在代码首次执行时,会将全局执行上下文放入栈底,而后再依据函数调用,向栈顶中压入函数执行上下文。当栈顶函数运行实现后,其对应的函数执行上下文将会从执行栈中 Pop 出,上下文控制权将移到以后执行栈的下一个执行上下文。
var a = 'Hello World!';
function first() {console.log('Inside first function');
second();
console.log('Again inside first function');
}
function second() {console.log('Inside second function');
}
first();
console.log('Inside Global Execution Context');
// Inside first function
// Inside second function
// Again inside first function
// Inside Global Execution Context
执行上下文的创立
执行上下文的创立分为三个阶段:
- 确定 this 指向
- 创立词法环境
- 创立变量环境
确定 this 指向
- 全局上下文中,this 指向全局对象,在浏览器中,this 指向 window 对象,在 nodejs 中,this 指向文件所在的 module;
- 函数上下文中,this 的指向须要看函数的调用形式。
创立词法环境
词法环境由两个局部组成:
- 环境记录:存储定义的变量和函数;
- 对外部环境的援用:能够拜访的内部词法环境
词法环境又能够分为:
- 全局环境:是一个没有外部环境的词法环境,所以对外部环境的援用为 null,领有全局对象(window)及其关联的属性和办法以及用户自定义全局变量;
- 函数环境:对外部环境的援用能够是全局环境或者函数环境,用户在函数中定义的变量存储在环境记录当中。
能够看上面的伪代码更加直观:
GobelExectionContext = { // 全局执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Object", // 对象环境记录
......
},
outer: <null> // 对外部环境的援用
}
}
FunctionExectionContext = { // 函数执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Declarative", // 申明性环境记录
......
},
outer: <GobelEvironment or FunctionEvironment> // 对外部环境的援用
}
}
创立变量环境
变量环境也是一个词法环境,所以它有下面词法环境所领有的属性。
在 es6 中,变量环境和词法环境的区别在于,前者用于存储 var 定义的变量,后者用于存储申明的函数和变量(let,const)。
能够看上面例子:
let a = 20;
const b = 30;
var c;
function multiply(e, f) {
var g = 20;
return e * f * g;
}
c = multiply(20, 30);
执行上下文如下:
GobelExectionContext = { // 全局执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Object", // 对象环境记录
a: < uninitialized >,
b: < uninitialized >,
multiply: < func >
},
outer: <null> // 对外部环境的援用
}
VariableEnvironment: { // 变量环境
EnvironmentRecord: {
Type: "Object", // 对象环境记录
c: undefined,
}
outer: <null>
}
}
FunctionExectionContext = { // 函数执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Declarative", // 申明性环境记录
Arguments: {0: 20, 1: 30, length: 2},
},
outer: <GobelLexicalEvironment>
}
VariableEnvironment: {
EnvironmentRecord: {
Type: "Declarative", // 申明性环境记录
g: undefined,
}
outer: <GobelLexicalEvironment>
}
}
这里能够看出 变量晋升 的起因:变量贮存在变量环境中为 undefine(应用 var 申明);变量贮存在词法环境中为 uninitialized(应用 let 和 const 申明),所以在应用 let 和 const 申明之前应用变量会报错。
执行上下文的执行
在此阶段实现对变量的赋值,即下面的执行上下文将变成:
GobelExectionContext = { // 全局执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Object", // 对象环境记录
a: 20,
b: 30,
multiply: < func >
},
outer: <null> // 对外部环境的援用
}
VariableEnvironment: { // 变量环境
EnvironmentRecord: {
Type: "Object", // 对象环境记录
c: <multiply>,
}
outer: <null>
}
}
FunctionExectionContext = { // 函数执行上下文
LexicalEnvironment: { // 词法环境
EnvironmentRecord: { // 环境记录
Type: "Declarative", // 申明性环境记录
Arguments: {0: 20, 1: 30, length: 2},
},
outer: <GobelLexicalEvironment>
}
VariableEnvironment: {
EnvironmentRecord: {
Type: "Declarative", // 申明性环境记录
g: 20,
}
outer: <GobelLexicalEvironment>
}
}
以上内容均为作者集体了解,如有谬误,请各位多多指出!
参考资料:
一篇文章看懂 JS 执行上下文
了解 JavaScript 中的执行上下文和执行栈
js 没那么简略(1)– 执行上下文
js 预编译