理解Javascript_12_执行模型浅析

简单的开始
简单的代码:


代码如下:

<script type="text/javascript" src="xxx.js"></script>
<script type="text/javascript">
var i = 10;
function say(msg){
alert(msg);
}
</script>
<script type="text/javascript">
j=100;
say("hello world");
</script>

上面代码段的运行顺序是:


代码如下:

step1. 读入第一个代码段
step2. 做语法分析,有错则报语法错误(比如括号不匹配等),并跳转到step5
step3. 创建全局执行环境(对var变量和function定义做"预解析")
step4. 执行代码段(调用函数、进入eval时,都会创建新的执行环境),有错则报错(比如变量未定义)
step5. 如果还有下一个代码段,则读入下一个代码段,重复step2
step6. 结束

对于step1中的'脚本段'指的是<script>... ...</script>标签中的内容,还包括外部引入的脚本文件,如<script src="xxx.js"></script>也被列是脚本段的范畴。那step2中的语法分析又是什么呢?简单的理解语法分析就是查看Javascript代码的语法结构是否正确。如:


代码如下:

<script type="text/javascript">
var a = 10;
if(a>10{
alert('yes');
}
</script>

很明显,代码无法通过语法分析,if这个条件语句的输写语法是错误的。step3和step4中的'执行环境'是指什么,全局执行环境和调用函数创建的执行环境有什么区别?执行环境内部又有哪些处理?... ...

注:下面的部分内容为原来《javascript提速_01_引用变量优化》一文中的前两节的完整版本。

关于执行环境(Execution Context)
所有 JavaScript 代码都是在一个执行环境中被执行的。它是一个概念,一种机制,用来完成JavaScript运行时作用域、生存期等方面的处理。

可执行的JavaScript代码分三种类型:
1. Global Code,即全局的、不在任何函数里面的代码,例如:一个js文件、嵌入在HTML页面中的js代码等。
2. Eval Code,即使用eval()函数动态执行的JS代码。
3. Function Code,即用户自定义函数中的函数体JS代码。
不同类型的JavaScript代码具有不同的Execution Context

在一个页面中,第一次载入JS代码时创建一个全局执行环境,当调用一个 JavaScript 函数时,该函数就会进入相应的执行环境。如果又调用了另外一个函数(或者递归地调用同一个函数),则又会创建一个新的执行环境,并且在函数调用期间执行过程都处于该环境中。当调用的函数返回后,执行过程会返回原始执行环境。因而,运行中的 JavaScript 代码就构成了一个执行环境栈。

让我们来看一个示例:


代码如下:

<script type="text/javascript">
function Fn1(){
function Fn2(){
alert(document.body.tagName);//BODY
//other code...
}
Fn2();
}
Fn1();
//code here
</script>


以上是程序从上到下执行时的执行环境栈情况图。

补充说明:
全局执行环境对应的是Global Code(全局代码)
Fn1执行环境、Fn2执行环境通称为函数执行环境对应的是Function Code(函数定义代码)

程序在进入每个执行环境的时候都会创建一个叫做Variable Object的对象。
针对于函数执行环境,函数对应的每一个参数、局部变量、内部方法都会在Variable Object上创建一个属性,属性名为变量名,属性值为变量值。针对于全局执行环境,具有相同的行为。但是要强调的一点是在全局执行环境中Varible Object就是Global Object,关于Global Object在《理解Javascript_03_javascript全局观》中已经说明了,可以简单的理解为window对象。这也就解释了全局方法和全局变量为什么都是window对象的属性或方法的原因,请看如下代码:


代码如下:

var num = 123;
alert(window.num);//123
function say(msg){
alert(msg);
}
window.say("hello");//hello

最后要说的是,Variable Object对象是一个内部对象,JS代码中无法直接访问。

关于Scope/Scope Chain
在访问变量时,就必须存在一个可见性的问题,这就是Scope。更深入的说,当访问一个变量或调用一个函数时,JavaScript引擎将不同执行位置上的Variable Object按照规则构建一个链表,在访问一个变量时,先在链表的第一个Variable Object上查找,如果没有找到则继续在第二个Variable Object上查找,直到搜索结束。这也就形成了Scope Chain的概念。

作用域链图,清楚的表达了执行环境与作用域的关系(一一对应的关系),作用域与作用域之间的关系(链表结构,由上至下的关系)。

注:本文仅仅从全局角度的看待javascript执行模型,因此不够深入,具体执行细节,请参见后续博文。

参考:
http://www.cnblogs.com/RicCC/archive/2008/02/15/JavaScript-Object-Model-Execution-Model.html
http://www.cn-cuckoo.com/2007/08/01/understand-javascript-closures-72.html
http://lifesinger.org/blog/2009/01/javascript-run-mechanism/

(0)

相关推荐

  • 理解Javascript_14_函数形式参数与arguments

    注:在阅读本博文前请先阅读<理解javascript_13_执行模型详解> 注:本文的部分内容是自已的一些推论,并无官文文档作依据,如有错误之后,还望指正. 生涩的代码 我们先来看一段比较生涩的代码: 复制代码 代码如下: function say(msg,other,garbage){ alert(arguments[1]);//world var other = 'nice to meet you!'; var msg; alert(arguments.length); alert(msg

  • 理解Javascript_05_原型继承原理

    prototype与[[prototype]] 在有面象对象基础的前提下,来看一段代码: 复制代码 代码如下: //Animal构造函数 function Animal(name){ this.name = name; } //Animal原型对象 Animal.prototype = { id:"Animal", sleep:function(){ alert("sleep"); } } var dog = new Animal("旺才");

  • 理解Javascript_01_理解内存分配原理分析

    原始值和引用值 在ECMAScript中,变量可以存放两种类型的值,即原始值和引用值. 原始值指的就是代表原始数据类型(基本数据类型)的值,即Undefined,Null,Number,String,Boolean类型所表示的值. 引用值指的就是复合数据类型的值,即Object,Function,Array,以及自定义对象,等等 栈和堆 与原始值与引用值对应存在两种结构的内存即栈和堆 栈是一种后进先出的数据结构,在javascript中可以通过Array来模拟栈的行为 复制代码 代码如下: va

  • 理解Javascript_03_javascript全局观

    先来看一张图吧: 解释一下: 核心(ECMAScript):定义了脚本语言的所有对象,属性和方法 文档对象模型(DOM):HTML和XML应用程序接口 浏览器对象模型(BOM):对浏览器窗口进行访问操作 现在来具体的讲一个各个成分: 关于ECMAScript ECMAScript的工作是定义语法和对象,从最基本的数据类型.条件语句.关键字.保留字到异常处理和对象定义都是它的范畴. 在ECMAScript范畴内定义的对象也叫做原生对象. 其实上它就是一套定义了语法规则的接口,然后由不同的浏览器对其

  • 理解Javascript_06_理解对象的创建过程

    简单的代码 我们先来看一段简单的代码: 复制代码 代码如下: function HumanCloning(){ } HumanCloning.prototype ={ name:'笨蛋的座右铭' } var clone01 = new HumanCloning(); alert(clone01.name);//'笨蛋的座右铭' alert(clone01 instanceof HumanCloning);//true HumanCloning.prototype = {}; alert(clon

  • 理解Javascript_13_执行模型详解

    函数执行环境 简单的代码: 复制代码 代码如下: function say(msg,other){ var str = "nobody say:"; this.name = '笨蛋的座右铭'; function method(){};//var method = function(){}; alert(str+msg); } say('hello world'); alert(name);//笨蛋的座右铭 当调用say方法时,第一步是创建其执行环境,在创建执行环境的过程中,会按照定义的

  • 理解Javascript_08_函数对象

    函数对象 首先,大家得明确一个概念:函数就是对象,代表函数的对象就是函数对象.既然是对象,那它又是被谁构造出来的呢?下面我们来看一段描述:JavaScript代码中定义函数,或者调用Function创建函数时,最终都会以类似这样的形式调用Function函数:var newFun=Function(funArgs, funBody); .由此可知函数对象是由Function这个函数对象构造出来的. 注:Function对象本身也是一个函数,因此它也一个函数对象.关于Function的深入理解,请

  • 理解Javascript_11_constructor实现原理

    constructor是什么 简单的理解,constructor指的就是对象的构造函数.请看如下示例: 复制代码 代码如下: function Foo(){}; var foo = new Foo(); alert(foo.constructor);//Foo alert(Foo.constructor);//Function alert(Object.constructor);//Function alert(Function.constructor);//Function 对于foo.con

  • 理解Javascript_09_Function与Object

    注:理论过于深入,本人不改保证所有的理论都是正确的,但经过多方测试还未发现实际代码与理论冲突的问题.如有错误,望高人指点! Function 首先回顾一下函数对象的概念,函数就是对象,代表函数的对象就是函数对象.所有的函数对象是被Function这个函数对象构造出来的.也就是说,Function是最顶层的构造器.它构造了系统中所有的对象,包括用户自定义对象,系统内置对象,甚至包括它自已.这也表明Function具有自举性(自已构造自己的能力).这也间接决定了Function的[[call]]和[

  • 理解Javascript_07_理解instanceof实现原理

    那么instanceof的这种行为到底是如何实现的呢,现在让我们揭开instanceof背后的迷雾. instanceof原理 照惯例,我们先来看一段代码: 复制代码 代码如下: function Cat(){} Cat.prototype = {} function Dog(){} Dog.prototype ={} var dog1 = new Dog(); alert(dog1 instanceof Dog);//true alert(dog1 instanceof Object);//t

  • 理解Javascript_02_理解undefined和null

    来自普遍的回答: 其实在 ECMAScript 的原始类型中,是有Undefined 和 Null 类型的. 这两种类型都分别对应了属于自己的唯一专用值,即undefined 和 null. 值 undefined 实际上是从值 null 派生来的,因此 ECMAScript 把它们定义为相等的,通过下列代码可以验证这一结论: alert(undefined == null); //true 尽管这两个值相等,但它们的含义不同. undefined 是声明了变量但未对其初始化时赋予该变量的值,n

  • 理解Javascript_10_对象模型

    对象模型 红色虚线表示隐式Prototype链. 这张对象模型图中包含了太多东西,不少地方需要仔细体会,可以写些测试代码进行验证.彻底理解了这张图,对JavaScript语言的了解也就差不多了.下面是一些补充说明: 1. 图中有好几个地方提到build-in Function constructor,这是同一个对象,可以测试验证: 复制代码 代码如下: //Passed in FF2.0, IE7, Opera9.25, Safari3.0.4 Function==Function.constr

  • 理解Javascript_15_作用域分配与变量访问规则,再送个闭包

    作用域分配与变量访问规则 在 ECMAScript 中,函数也是对象.函数对象在变量实例化过程中会根据函数声明来创建,或者是在计算函数表达式或调用 Function 构造函数时创建.(关于'函数对象'请见<理解Javascript_08_函数对象>).每个函数对象都有一个内部的 [[scope]] 属性,这个属性也由对象列表(链)组成.这个内部的[[scope]] 属性引用的就是创建它们的执行环境的作用域链,同时,当前执行环境的活动对象被添加到该对象列表的顶部.当我们在函数内部访问变量时,其实

随机推荐