深入全面理解JavaScript的执行上下文_蓝戒的博客


深入全面理解JavaScript的执行上下文

1.什么是javascript的执行上下文(e xecution context)?
执行上下文可以认为是 代码的执行环境。
在JavaScript中有三种代码运行环境:
1)全局级别的代码 – 这个是默认的代码运行环境,一旦代码被载入,js引擎最先进入的就是这个环境,js解释器 创建一个 全局的执行上下文。
2)函数级别的代码 – 当执行一个函数时,运行函数体中的代码,会创建一个 函数的执行上下文。
3)Eval的代码 – 在Eval函数内运行的代码,创建 一个 eval 执行上下文。

为了表示不同的运行环境,JavaScript中有一个执行上下文(E xecution context,EC)的概念。也就是说,当JavaScript代码执行的时候,会进入不同的执行上下文,这些执行上下文就构成了一个执行上下文栈(E xecution context stack,ECS)。

2.执行上下文的建立过程?

2.1 当js解释器开始工作的时候:
1) 首先创建一个 执行上下文栈(后进先出)
2) 接着创建一个 全局的执行上下文,并放入执行上下文栈中。
3) 当在全局上下文中调用一个函数的时候.
为函数创建一个 执行上下文,
压入执行上下文栈中。
4) 当函数执行结束的时候,位于栈顶的 执行上下文 被弹出。继续执行 新的位于栈顶的执行上下文。

这种方式保证了 任意时刻都只有位于栈顶的执行上下文才会被执行,也就是实现了单线程。

2.2 执行上下文建立分成两个阶段:

创建阶段(进入执行上下文)和执行阶段(激活/执行代码)。

1)、创建阶段:发生在函数调用时,但是在执行具体代码之前(比如,对函数参数进行具体化之前)
创建变量,函数,arguments对象,参数。
创建作用域链(Scope Chain)。
确定this的赋值。
2)、执行阶段:
变量赋值
函数引用
解释/执行其他代码。
实际上,可以把执行上下文看做一个对象。
对于每个执行上下文都有三个重要的属性,变量对象(Variable object,VO),作用域链(Scope chain)和this。这三个属性跟代码运行的行为有很重要的关系。

3. 理解执行上下文栈
在浏览器中,javascript引擎的工作方式是单线程的。也就是说,某一时刻只有唯一的一个事件是被激活处理的,其它的事件被放入队列中,等待被处理。下面的示例图描述了这样的一个堆栈:

ec

当javascript代码文件被浏览器载入后,默认最先进入的是一个全局的执行上下文。当在全局上下文中调用执行一个函数时,程序流就进入该被调用函数内,此时引擎就会为该函数创建一个新的执行上下文,并且将其压入到执行上下文堆栈的顶部。浏览器总是执行当前在堆栈顶部的上下文,一旦执行完毕,该上下文就会从堆栈顶部被弹出,然后,进入其下的上下文执行代码。这样,堆栈中的上下文就会被依次执行并且弹出堆栈,直到回到全局的上下文。

对于执行上下文这个抽象的概念,可以归纳为以下几点:
1)单线程
2)同步执行
3)唯一的一个全局上下文
4)函数的执行上下文的个数没有限制
5)每次某个函数被调用,就会有个新的执行上下文为其创建,即使是调用的自身函数,也是如此。

4.执行上下文过程的详细分析
执行上下文对象(上述的e xecutionContextObj)是在函数被调用时,但是在函数体被真正执行以前所创建的。函数被调用时,就是我上述所描述的两个阶段中的第一个阶段 – 建立阶段。这个时刻,引擎会检查函数中的参数,声明的变量以及内部函数,然后基于这些信息建立执行上下文对象(e xecutionContextObj)。在这个阶段,variableObject对象,作用域链,以及this所指向的对象都会被确定。

上述第一个阶段的具体过程如下:

1)找到当前上下文中的调用函数的代码
2)在执行被调用的函数体中的代码以前,开始创建执行上下文
3)进入第一个阶段-建立阶段:

建立variableObject对象:
建立arguments对象,检查当前上下文中的参数,建立该对象下的属性以及属性值
检查当前上下文中的函数声明:
每找到一个函数声明,就在variableObject下面用函数名建立一个属性,属性值就是指向该函数在内存中的地址的一个引用。

如果上述函数名已经存在于variableObject下,那么对应的属性值会被新的引用所覆盖。

初始化作用域链
确定上下文中this的指向对象

4)代码执行阶段:
执行函数体中的代码,逐行运行代码,给variableObject中的变量属性赋值。
在建立阶段,除了arguments,函数的声明,以及参数被赋予了具体的属性值,其它的变量属性默认的都是undefined。一旦上述建立阶段结束,引擎就会进入代码执行阶段,在代码执行阶段,变量属性才会被赋予具体的值。

5.VO和AO:
在执行上下文中,会保存变量对象(Variable object,VO)
5.1变量对象(Variable object,VO

变量对象是与执行上下文相关的数据作用域。它是一个与上下文相关的特殊对象,其中存储了在上下文中定义的变量和函数声明。也就是说,一般VO中会包含以下信息:

变量 (var, Variable Declaration);
函数声明 (Function Declaration, FD);
函数的形参
当JavaScript代码运行中,如果试图寻找一个变量的时候,就会首先查找VO

对于VO,是有下面两种特殊情况的:

函数表达式(与函数声明相对)不包含在VO之中
没有使用var声明的变量(这种变量是,”全局”的声明方式,只是给Global添加了一个属性,并不在VO中)

5.2活动对象(Activation object,AO)
只有全局上下文的变量对象允许通过VO的属性名称间接访问;在函数执行上下文中,VO是不能直接访问的,此时由激活对象(Activation Object,缩写为AO)扮演VO的角色。激活对象 是在进入函数上下文时刻被创建的,它通过函数的arguments属性初始化。

Arguments Objects 是函数上下文里的激活对象AO中的内部对象,它包括下列属性:

callee:指向当前函数的引用
length: 真正传递的参数的个数
properties-indexes:就是函数的参数值(按参数列表从左到右排列)
对于VO和AO的关系可以理解为,VO在不同的执行上下文中会有不同的表现:当在全局执行上下文中,可以直接使用VO;但是,在函数执行上下文中,AO就会被创建。

参考资料:

1. http://www.cnblogs.com/lin-js/p/5293418.html

2. http://www.jb51.net/article/75032.htm

3. http://web.jobbole.com/84044/

本文固定链接: http://www.webzsky.com/?p=1138 | 蓝戒的博客

cywcd
该日志由 cywcd 于2017年07月12日发表在 javascript 分类下, 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
原创文章转载请注明: 深入全面理解JavaScript的执行上下文 | 蓝戒的博客
关键字: ,

深入全面理解JavaScript的执行上下文:等您坐沙发呢!

发表评论


快捷键:Ctrl+Enter
来自的朋友,欢迎您 点击这里 订阅我的博客 o(∩_∩)o~~~
×