执行上下文(Execution Context)
每次当控制器转到可执行代码的时候,就会进入一个执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。JavaScript中的运行环境大致分为三种:
- 全局环境:JavaScript代码运行起来会首先进入的环境
- 函数环境:当函数被调用的时候,会进入当前的函数中执行代码
- eval(不建议使用,忽略)
JavaScript中会使用栈的方式处理它们,这个栈,被称之为函数调用栈(call stack)。栈底永远都是全局上下文,栈顶就是当前的执行上下文。当代码在执行的过程中,遇到上面的三种情况,都会生成一个上下文并将其压入调用栈中·。而当处于栈顶的上下文执行完毕之后,就会自动出栈。
var color = 'blue';
function changeColor() {
var anotherColor = 'red';
function swapColors() {
var tempColor = anotherColor;
anotherColor = color;
color = tempColor;
}
swapColors();
}
changeColor();
首先是全局上下文入栈,然后可执行代码开始执行,直到碰到changeColor(),激活了函数changeColor创建它的执行上下文,所以此时changeColor执行上下文入栈。
changeColor执行上下文入栈之后,控制器开始执行其中的可执行代码。直到碰到swapColors(),激活了函数swapColors创建它的执行上下文,所以此时swapColors执行上下文入栈。
swapColors执行上下文中的可执行代码中,再也没有可以生成执行上下文的情况,所以代码顺利执行完毕,然后出栈。再接着是changeColor中也没有了可以生成执行上下文的情况,也顺利执行完代码后出栈。这时,ECStack中只有全局上下文了。全局上下文在浏览器关闭后出栈。
在函数中,如果碰到return会直接终止可执行代码的执行,并将当前上下文弹出栈
执行上下文的一些结论
- 单线程
- 同步执行 ,只有栈顶的当前上下文处于执行状态,其余上下文需要等待
- 全局上下文只有唯一的一个,它在浏览器关闭时出栈
- 函数的执行上下文没有个数限制
- 每次函数被调用时,就会创建一个执行上下文,即使是调用自身的函数。
下面有一个闭包例子,强化理解执行上下文
function f1(){
var n=999;
function f2(){
alert(n);
}
return f2;
}
var result=f1();
result();
f1中的函数f2,在f1被调用执行的过程中并没有被调用,所以不会创建上下文,而是等result调用执行时才会创建上下文。
当一个函数被调用的时候(激活),它的执行上下文就会被创建。而一个执行上下文的生命周期可以分为两个阶段。
- 创建阶段 在这个阶段,执行上下文会分别创建变量对象,建立作用域链,以及确定this的指向。
- 代码执行阶段 创建完成之后,就会开始执行代码,这个时候,就会完成变量赋值,函数引用,以及执行其它可执行代码。
- 范围:一段
<script>
或者一个函数 - 全局:一段
<script>
(变量对象和this都是window) - 函数:一个函数(变量对象,this)
- arguments对象是对应于传递给函数的参数的类数组对象
- 是所有(非箭头)函数中都可以用的局部变量