执行上下文,即context,也不知道是谁翻译的,很多的文献、书籍用的都是这个词。还记得第一次接触这个词时的惆怅、迷惘、不知所措,扶了扶眼镜,翻开大辞典,仍是翻译成环境比较接地气。JS执行上下文,即JS的执行环境。web
当咱们的代码执行时,会进入到不一样的执行上下文,即不一样的环境。在不一样的环境中,有着不一样的 scope(做用域),代码所能访问到的资源也就不一样。 在 JS 中,执行环境有以下三种状况:浏览器
全局环境bash
代码默认运行的环境,代码执行时会首先进入全局环境。它是最外围的一个执行环境,根据 ECMAScript 实现所在的宿主环境的不一样,表示全局环境的对象也不同。在 web 浏览器中,全局环境就是 window 对象。全局变量和函数都是做为全局对象 window 的变量和方法来建立的。函数
函数环境post
函数被调用执行时,所建立的执行环境。ui
evalthis
使用 eval 会进入一个新的执行环境,它的变量对象为全局变量对象或调用者的变量对象。因为 eval 的毒瘤属性,通常不推荐使用,可忽略。spa
某个执行环境中的全部代码执行完毕后,该环境被销毁,保存在环境中的变量和函数也随之销毁。这些变量和函数保存在一个叫作变量对象的对象(variableObject)中,关于变量对象将在变量对象与做用域链一文做详细探讨。线程
执行环境的生命周期大概分为两个阶段,即建立阶段和执行阶段:翻译
1. 建立阶段
由此,一个执行环境能够由包含做用域链、变量对象和 this 指针的对象组成:
executionContextObj = {
scopeChain: {},
variableObject: {},
this: {}
}
复制代码
2. 代码执行阶段
浏览器中的解释器被实现为单线程,同一时间只能处理一个任务,JS 程序中多个执行环境会以栈的方式来处理,这个栈叫作执行栈。栈底永远都是全局环境(窗口关闭时弹出),栈顶就是当前正在执行的环境。前述三种状况都会建立执行环境,执行环境建立时会被压入栈顶,成为一个运行(活动)的环境,位于栈顶的环境执行完毕后就从栈顶弹出,并将环境控制权交给调用者(以前的栈),而调用者继续执行(或激活其余环境),直到它的执行环境结束。ECMAScript 程序中的执行流正是由这个方便的机制控制着。
来看下面的例子:
var firstName = 'snow';
function getName() {
var lastName = 'John';
function fullName() {
var name = lastName + firstName;
return name;
}
var name = fullName();
return name;
}
getName();
复制代码
其执行栈变化过程以下:
首先,将全局环境压入栈,开始执行代码,
直到遇到getName()
,准备调用函数,建立函数 getName 的执行环境,将其压入栈顶并开始执行函数
直到遇到fullName()
,准备调用函数,建立函数 fullName 的执行环境,将其压入栈顶并开始执行函数
函数 fullName 执行时没有再生成执行环境,执行完毕后则从栈顶弹出
fullName 执行栈弹出后,控制权回到了 getName 的执行栈,继续执行代码,执行完毕,从栈顶弹出
最后回到了全局环境,窗口关闭后弹出