理解JavaScript执行环境,Execution Context

理解JavaScript执行环境(Execution Context)

1.概念

执行环境(Execution Context)是一个抽象的概念,用于规定ECMAScript实现时要求的行为。ECMAScript规范没有指明任何关于如何实现execution context,但是execution context包含参考在规范定义的结构的相关属性,所以execution context可

以被设想成(甚至被实现)带有属性(虽然这些属性不是public属性)的对象。

2.分类

所有的JavaScript代码都是在execution context中执行的。全局代码(内置的执行代码,通常作为一个JS文件或HTML页面加载)在全局execution context中执行,每一个函数(可能作为一个构造函数)调用都有与之关联的execution context。

通过eval函数执行的代码也有一个完全不同的execution context,但因为JavaScript程序员在通常情况下不会使用eval函数,所以这里不作讨论。

3.Execution context栈

当一个函数被调用时,此函数就会进入一个execution context,如果另一个函数被调用(或递归地调用相同的函数),就会创建一个新execution context,在函数调用时一直在此execution context中执行。当被调用的函数返回时,程序返回到之前的

execution context。因此,运行中的javascript代码就形成了一个execution context栈。

4.函数execution context创建过程

当一个execution context被创建时,一系列的事情按照一个规定的顺序发生。

4.1活动对象

首先,在一个函数的execution context中,全创建一个活动(“Activation”)对象。这个活动对象是另一个规范机制,活动对象之所以能够被作为一个对象是因为它最终包含可访问的命名属性,虽然它是一个普通的对象,因为它没有prototype,并它

不能直接通过javascript code来被引用。

4.2arguments对象

为函数调用创建execution context下一步就是创建一个arguments对象,它是一个类数组对象,通过整数下标索引按顺序与调用函数时传递的参数对应。它同时包含了length和callee属性。然后,为活动对象创建一个名为"arguments"的属性并且将前面

arguments对象引用赋给这个arguments属性。

4.3作用域链

接下来为execution context分配scope(作用域),这个作用域由一个对象列表(链)组成。每个函数都有一个内部的[[scope]]属性,这个属性也是由一个对象列表(链)构成。分配给调用函数execution context的scope由函数对象的[[scope]]所引用

的对象列表(链)组成,同时,函数的活动对象被添加到链的前端(列表的顶部)。

4.4变量实例化

之后会发生由ECMA 262所谓“Variable”对象完成"变量实例化"的过程。然而,活动对象被作为“Variable”对象,函数的每个形参都会为之创建相应的“Variable”对象的命名属性。传递给函数的参数值对相应的命名属性赋值(否,赋值为

undefined)。根据内部函数的定义,为“Variable”对象创建与该函数声明名称的同名属性,而相应创建的函数对象赋给这个属性。变量实例化的最后一步就是将函数内部声明的所有局部变量创建相应的Variable对象的命名属性。

在变量实例化过程中与局部变量对应的Variable对象的命名属性被初始化为undefined值。局部变量直到函数体代码在执行期间,相关的赋值表达式求值时才被真实地实例化。

事实上,包含arguments属的活动对象与包含局部变量的Variable对象是同一个对象,因此可以将arguments作为函数的局部变量看待。

4.5this

最后,为使用的this赋值。如果this被赋值为对象,那么使用this使用为前缀访问的属性相当于访问相应对象的属性。如果被赋值(内部地)为null,则this将会引用全局对象。

5.全局execution context

全局execution context稍微不同,因为它没有参数,所以不需要定义引用这些参数的活动对象。全局execution context也需要一个作用域,而它的作用域链实际上只由一个对象(全局对象)组成。全局execution context也有变量实例化过程,内部函数

就是涉及大部分JavaScript代码的、常规的顶级函数声明。在变量实现化过程中,全局对象就是Variable对象,这就是为什么全局声明的函数是全局对象的属性的原因。全局的变量同样如此。

全局execution context也会使用this对象来引用全局对象。