最近看到的一篇文章,讲到了javascript中基础但及其重要的一个概念:执行环境,并且用栈的理论描述
,非常深入,相信你看过之后能极好的理解javascript函数运行机制。也为javascript的作用域链等概念打
好基础。
在这篇文章中我将深入的分析javascript中最为基础的一个概念------执行环境,在读完该文章后,我希望
你能对执行环境有一个清晰和深入的认识,并且能够彻底明白一些问题:比如为什么变量和函数能够在
他们声明之前使用以及他们的值如何确定。
当一段代码执行的时候,明白他处于何种环境是非常有必要的,一般来说javascript代码分为三种:
- 全局代码:这是默认的代码类型
- 函数代码:进入一个函数体所执行的代码
- eval代码:用eval执行的代码
看下面的一段代码
紫色代表全局上下文,绿色、蓝色和橙色代表3个不同的函数执行上下文。在一个程序中,全局上下文只有
一个,他是在代码执行前创建的,并且可以被其他上下文访问到,而函数执行上下文则有多个。
执行上下文栈的概念
一般来说,javascript的解释引擎在进行代码运行时是单线程的,也就是说在同一时间只会有一个任务在运行,
比如,在一个函数调用另一个函数时,调用者只有在被调用者执行完毕后才能再次执行,否则他是被挂起的。
其他待执行的任务就形成了一个队列,表现在javascript引擎中就是一个栈。栈很好的实现了这种机制。
我们知道,在代码首次被载入时,会创建一个全局上下文,当调用一个函数时,会创建一个函数执行
上下文,并把这个上下文环境置于栈的顶端,成为当前的活动栈。同理,如果该函数又调用了另外一个
函数,那么被调用的函数会形成一个新的执行上下文,并被推入栈顶。当该函数执行完毕返回后,会被
弹出该栈,从而使第二个执行环境代码得以执行。
(function foo(i) {
if (i === 3) {
return;
}
else {
foo(++i);
}
}(0));

该函数被调用了四次,那么相应的会形成四个执行环境。当条件满足时,函数停止执行,并按
顺序返回结果,最后全部被弹出该栈,仅剩一个全局上下文。
关于执行上下文,有5个关键点:
- 单线程
- 异步执行
- 仅有一个全局上下文
- 不限制函数上下文
- 每次函数调用形成一个独立的执行环境,即使调用自身
执行环境结构详解
对于解释引擎来说,构造一个执行环境一般分为两个步骤:
创建阶段:当调用一个函数时,不会立即执行其中的代码,而会有一些准备工作
- 创建变量,函数和参数
- 构造作用域链
- 设置this的值
执行阶段
对变量赋值,并执行函数代码
其实,我们可以认为一个执行环境是一个拥有3个属性的对象。
执行环境对象= {
变量对象: { 参数、内部变量、函数声明 },
作用域链: { 本函数变量对象+所有的父级变量对象},
this值: {}
}