一、什么是执行上下文?
简而言之,执行上下文是评估和执行 JavaScript 代码的环境的抽象概念。每当 Javascript 代码在运行的时候,它都是在执行上下文中运行。
二、执行上下文的类型
JavaScript 中有包含三种类型。
- 全局执行上下文 — 这是默认或者说基础的上下文,任何不在函数内部的代码都在全局上下文中。它会执行两件事:创建一个全局的 window 对象(浏览器的情况下),并且设置
this
的值等于这个全局对象。一个程序中只会有一个全局执行上下文。 - 函数执行上下文 — 每当一个函数被调用时, 都会为该函数创建一个新的上下文。每个函数都有它自己的执行上下文,不过是在函数被调用时创建的。函数上下文可以有任意多个。每当一个新的执行上下文被创建,它会按定义的顺序执行一系列步骤。
- Eval 函数执行上下文 — 执行在
eval
函数内部的代码也会有它属于自己的执行上下文,但由于 JavaScript 开发者并不经常使用eval
,所以在这里我不会讨论它。
JS是单线程的,运行在全局执行上下文,每进入一个function,就做一次入栈操作,向栈顶压入一个属于该function的新的执行上下文。若function中又调用了另一个function,则再执行一次入栈…依次执行完再依次出栈,回到全局执行上下文。全局执行上下文一定是在栈底,在浏览器关闭后出栈。
执行上下文,出入栈图解:
执行上下文的构成如下图:
执行上下文由变量对象、作用域链、this构成;
- 变量对象VO(Variable Object)保存此执行上下文中涉及到的变量(变量对象详细总结)
变量对象会包括:
-
函数的所有形参 (如果是函数上下文)
- 由名称和对应值组成的一个变量对象的属性被创建
- 没有实参,属性值设为 undefined
-
函数声明
- 由名称和对应值(函数对象(function-object))组成一个变量对象的属性被创建
- 如果变量对象已经存在相同名称的属性,则完全替换这个属性
-
变量声明
- 由名称和对应值(undefined)组成一个变量对象的属性被创建;
- 如果变量名称跟已经声明的形式参数或函数相同,则变量声明不会干扰已经存在的这类属性
function test1(arg){
var a = 1;
var b = {name: 'afei'};
function c(){
console.log(a);
}
}
上面test1执行时创建的变量对象如下:
VO = {
arguments: {
0: 1,
length: 1
},
a: 1,
b: <b reference>,
c: <c reference>
}
- 作用域链保存着此执行上下文中的VO与其他执行上下文中的VO的关联关系(能否访问到)。
- this,在执行上下文被创建时,会确定this的指向。注意:
this
的值不会被保存在作用域链中,this
的值取决于函数被调用的时候的情景。