JavaScript的解析(预处理)与执行
详见:http://www.cnblogs.com/foodoi...
执行上下文
JavaScript在执行一个“代码段”之前,即解析(预处理)阶段,会先进行一些“准备工作”,例如扫描JS中var定义的变量、函数名等,进而生成执行上下文。
JS中的“代码段”分为三种:全局代码段、函数体代码段、eval代码段。(注:ES6之前,JS不存在“代码块”作用域的概念,即除了函数之外所有“{}”里的代码,都属于全局作用域)
全局代码段“准备工作”包括:
1.变量、函数表达式 —— 变量声明,默认赋值为undefined;
2.this —— 赋值;
3.函数声明 —— 赋值。
函数体代码段“准备工作”包括:
1.变量、函数表达式 —— 变量声明,默认赋值为undefined;
2.this —— 赋值;
3.函数声明 —— 赋值;
4.参数 —— 赋值;
5.argument —— 赋值;
6.自由变量的取值作用域 —— 赋值。
evel()不推荐使用,所以不再分析evel代码段。
至此,“执行上下文”的定义可以通俗化为 —— 在执行代码段之前(预处理阶段),把将要用到的所有变量都事先拿出来,有的直接赋值,有的先用undefined占个空,这些变量共同组成的词法环境,即为执行上下文环境。
在执行js代码时,会有数不清的函数调用次数,会产生许多个上下文环境。这么多上下文环境该如何管理,以及如何销毁并释放内存呢?这就需要“执行上下文栈”来解释了。
执行上下文栈
通过上文我们知道:预处理全局代码时,会产生一个执行上下文环境。每次调用函数的预处理时,都会产生一个执行上下文环境。其实,当这个函数调用完成时,它的执行上下文环境以及其中的数据就会被销毁,执行过程再重新回到全局上下文环境。同一时刻,处于活动状态的执行上下文环境只有一个。
实现这一压栈出栈过程的机制就是“执行上下文栈”。
执行上下文栈的压栈出栈过程实例代码:
var a = 10, //1.进入全局上下文环境
fn,
bar = function(x) {
var b = 5;
fn(x+b); //3.进入fn函数上下文环境
};
fn = function(y) {
var c = 5;
console.log(y+c);
}
bar(10); //2.进入bar函数上下文环境
预处理时,首先创建全局上下文环境:
然后执行代码,全局上下文环境中的变量都被赋值:
当执行到调用bar函数时,跳转到bar函数内部,对其进行预处理,创建bar函数的执行上下文环境:
并将这个函数上下文环境压栈,设置为活动状态,开始执行bar函数体内代码:
当执行到调用fn函数时,跳转到bar函数内部,对其进行预处理,创建fn函数的执行上下文环境,并压栈,设置为活动状态,开始执行fn函数体内代码:
fn函数执行完毕后,此次调用fn所生成的上下文环境出栈,并且被销毁(已经用完了,就要及时销毁,释放内存),bar函数的执行上下文环境回到活动状态:
bar函数执行完毕后,调用bar函数所生成的上下文环境出栈,并且被销毁(已经用完了,就要及时销毁,释放内存),全局上下文环境回到活动状态:
全局代码执行完成,全局上下文环境出栈,并且销毁(已经用完了,就要及时销毁,释放内存),代码执行完毕。
以上是一段代码执行上下文环境的完整变化过程,但有一种情况的代码,其执行上下文环境并未按上述过程销毁,这就是接下来我们的重点研究对象 —— 闭包!
要谈闭包,我们还得先认识下作用域和自由变量,敬请期待... ...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。