日期:2014-05-16  浏览次数:20334 次

JavaScript对象模型-执行模型(笔记3)

执行模型
执行上下文(Execution Context)简介
JavaScript代码运行的地方都存在执行上下文,它是一个概念,一种机制,用来完成JavaScript运行时作用域、生存期等方面的处理。执行上下文包括Variable Object、Variable Instatiation、Scope/Scope Chain等概念,在不同的场景/执行环境下,处理上存在一些差异,下面先对这些场景进行说明。

函数对象分为用户自定义函数对象和系统内置函数对象,对于用户自定义函数对象将按照下面描述的机制进行处理,但内置函数对象与具体实现相关,ECMA规范对它们执行上下文的处理没有要求,即它们基本不适合本节描述的内容。

执行的JavaScript代码分三种类型,后面会对这三种类型处理上不同的地方进行说明:
1. Global Code,即全局的、不在任何函数里面的代码,例如一个js文件、嵌入在HTML页面中的js代码等。
2. Eval Code,即使用eval()函数动态执行的JS代码。
3. Function Code,即用户自定义函数中的函数体JS代码。

基本原理
在用户自定义函数中,可以传入参数、在函数中定义局部变量,函数体代码可以使用这些入参、局部变量。背后的机制是什么样呢?
当JS执行流进入函数时,JavaScript引擎在内部创建一个对象,叫做Variable Object。对应函数的每一个参数,在Variable Object上添加一个属性,属性的名字、值与参数的名字、值相同。函数中每声明一个变量,也会在Variable Object上添加一个属性,名字就是变量名,因此为变量赋值就是给Variable Object对应的属性赋值。在函数中访问参数或者局部变量时,就是在variable Object上搜索相应的属性,返回其值
一般情况下Variable Object是一个内部对象,JS代码中无法直接访问。规范中对其实现方式也不做要求,因此它可能只是引擎内部的一种数据结构。

大致处理方式就这样,但作用域的概念不只这么简单,例如函数体中可以使用全局变量、函数嵌套定义时情况更复杂点。这些情况下怎样处理?JavaScript引擎将不同执行位置上的Variable Object按照规则构建一个链表,在访问一个变量时,先在链表的第一个Variable Object上查找,如果没有找到则继续在第二个Variable Object上查找,直到搜索结束。这就是Scope/Scope Chain的大致概念。//岂不是效率很低? ?还是我火星了.....

下面是各个方面详细的处理。

Global Object
JavaScript的运行环境都必须存在一个唯一的全局对象-Global Object,例如HTML中的window对象。Global Object是一个宿主对象,除了作为JavaScript运行时的全局容器应具备的职责外,ECMA规范对它没有额外要求。它包含Math、String、Date、parseInt等JavaScript中内置的全局对象、函数(都作为Global Object的属性),还可以包含其它宿主环境需要的一些属性。

Variable Object
上面简述了Variable Object的基本概念。创建Variable Object,将参数、局部变量设置为Variable Object属性的处理过程叫做Variable Instatiation-变量实例化,后面结合Scope Chain再进行详细说明。

Global Code
Variable Object就是Global Object,这是Variable Object唯一特殊的地方(指它是内部的无法访问的对象而言)。

var?globalVariable?=?"WWW";
document.write(window.globalVariable);?
//result:?WWW

上面代码在Global Code方式下运行,根据对Variable Object的处理,定义变量globalVariable时就会在Global Object(即window)对象上添加这个属性,所以输出是WWW这个值。

Function Code
Variable Object也叫做Activation Object(因为有一些差异存在,所以规范中重新取一个名字以示区别,Global Code/Eval Code中叫Variable Object,Function Code中就叫做Activation Object)。
每次进入函数执行都会创建一个新的Activation Object对象,然后创建一个arguments对象并设置为Activation Object的属性,再进行Variable Instantiation处理
退出函数时,Activation Object会被丢弃(并不是内存释放,只是可以被垃圾回收了)

附arguments对象的属性:
length: 为实际传入参数的个数。注意,参考函数对象创建过程,函数对象上的length为函数定义时要求的参数个数
callee: 为执行的函数对象本身。目的是使函数对象能够引用自己,例如需要递归调用的地方。
function fnName(...) { ... }这样定义函数,它的递归调用可以在函数体内使用fnName完成。var fn=function(...) { ... }这样定义匿名函数,在函数体内无法使用名字引用自己,通过arguments.callee就可以引用自己而实现