文档章节

理解JavaScript的编译过程与运行机制

二分之一
 二分之一
发布于 2014/03/19 07:55
字数 1291
阅读 723
收藏 1

    JavaScript引擎,不是逐条解释执行javaScript代码,而是按照代码块一段段解释执行。所谓代码块就是使用<script>标签分隔的代码段。

一、编译阶段

对于常见编译型语言(例如:Java)来说,编译步骤分为:词法分析->语法分析->语义检查->代码优化和字节生成。

对于解释型语言(例如JavaScript)来说,通过词法分析和语法分析得到语法树后,就可以开始解释执行了。

(1)词法分析是将字符流(char stream)转换为记号流(token stream),就像英文句子一个个单词独立翻译,举例:

代码:var result = testNum1 - testNum2; 

词法分析后 :

  1. NAME "result"  
  2. EQUALS  
  3. NAME "testNum1"  
  4. MINUS  
  5. NAME "testNum2"  
  6. SEMICOLON 

(2)语法分析得到语法树,举例:

条件语句 if(typeof a == "undefined" ){ a = 0; } else { a = a; } alert(a);


当JavaScript解释器在构造语法树的时候,如果发现无法构造,就会报语法错误,并结束整个代码块的解析。

(3“预编译”(并非完全的顺序执行)

“function函数”是一等公民!编译阶段,会把定义式的函数优先执行,也会把所有var变量创建,默认值为undefined,以提高程序的执行效率!

总结:当JavaScript引擎解析脚本时,它会在预编译期对所有声明的变量和函数进行处理!并且是先预声明变量,再预定义函数!

二、JavaScript执行过程

 在解释过程中,JavaScript引擎是严格按着作用域机制(scope)来执行的。JavaScript语法采用的是词法作用域 (lexcical scope),也就是说JavaScript的变量和函数作用域是在定义时决定的,而不是执行时决定的,由于词法作用域取决于源代码结构,所以 JavaScript解释器只需要通过静态分析就能确定每个变量、函数的作用域,这种作用域也称为静态作用域(static scope)。补充:但需要注意,with和eval的语义无法仅通过静态技术实现,实际上,只能说JS的作用域机制非常接近lexical scope。

JavaScript中的变量作用域在函数体内有效,无作用域;

function func(){
    for(var i = 0; i < array.length; i++){  
       //do something here.  
    }  
    //此时i仍然有值,及I == array.length  
    print(i);//但在java语言中,则无效
}

    JavaScript引擎在执行每个函数实例时,都会创建一个执行环境(execution context)。执行环境中包含一个调用对象(call object), 调用对象是一个scriptObject结构(“运行期上下文”),用来保存内部变量表varDecls、内嵌函数表funDecls、父级引用列表upvalue等语法分析 结构(注意:varDecls和funDecls等信息是在语法分析阶段就已经得到,并保存在语法树中。函数实例执行时,会将这些信息从语法树复制到 scriptObject上)。scriptObject是与函数相关的一套静态系统,与函数实例的生命周期保持一致,函数执行完毕,该对象销毁。

    JavaScript引擎通过作用域链(scope chain)把多个嵌套的作用域串连在一起,并借助这个链条帮助JavaScript解释器检索变量的值。这个作用域链相当于一个索引表,并通过编号来存 储它们的嵌套关系。当JavaScript解释器检索变量的值,会按着这个索引编号进行快速查找,直到找到全局对象(global object)为止,如果没有找到值,则传递一个特殊的undefined值。

案例分析:

var scope = "global";
scopeTest();
function scopeTest(){  
    alert(scope);  
    var scope = "local";  
    alert(scope);  
}

打印结果:undefined,local;

分析:省略词法分析等过程...执行遇到函数调用scopeTest(),创建一个调用对象(运行期上下文,函数执行完毕,该对象销毁),构造它的作用域链时,搜索函数中用var声明的变量放入该链(在语法分析阶段就已经得到放在语法树中,此时只是拷贝过来),因此scope在整个函数scopeTest内都是可见的(从函数体的第一行到最后一行)。虽然函数scopeTest的作用域链上有全局对象,自然能够访问到全局的scope,但寻找变量时会沿着自身作用域链向上逐个找,因此首先找到自己的scope:undefined。

    如果函数引用了外部变量的值,则JavaScript引擎会为该函数创建一个闭包体(closure),闭包体是一个完全封闭和独立的作用域,它不会在函数调用完毕后就被JavaScript引擎当做垃圾进行回收。闭包体可以长期存在,因此开发人员常把闭包体当做内存中的蓄水池,专门用来长期保存变量的值。只有当闭包体的外部引用被全部设置为null值时,该闭包才会被回收。当然,也容易引发垃圾泛滥,甚至出现内存外溢的现象。





© 著作权归作者所有

共有 人打赏支持
二分之一
粉丝 12
博文 29
码字总数 9595
作品 0
唐山
程序员
通过DLS解析器,了解JS的编译原理

接触Javascript很长一段时间了,但一直浮在语言的表面,今天决定重头开始更深入的学习Javascript,先从Javascript的编译原理开始。 在程序的执行方式中有编译型和解释型,以前学习的C语言就是...

tryzf
06/30
0
0
Vue 全家桶,深入Vue 的世界

FinGet 26 日志 9 分类 15 标签 RSS GitHub E-Mail SegmentFault 推荐阅读 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理 前端进阶系列 八段代码彻底掌握 Promise 通俗大白话来理解...

FinGet
07/02
0
0
Vue.js异步更新及nextTick

写在前面 前段时间在写项目时对nextTick的使用有一些疑惑。在查阅各种资料之后,在这里总结一下Vue.js异步更新的策略以及nextTick的用途和原理。如有总结错误的地方,欢迎指出! 本文将从以下...

Jee
08/29
0
0
Node.js Event Loop与浏览器 Event Loop(事件环)

要理解Event Loop首先要学习几个概念,下面就通过这些概念来一步步解析Event Loop 一:进程与线程 进程是操作系统分配资源和调度任务的基本单位,线程是建立在进程上的一次程序运行单位,一个...

张文梦
06/07
0
0
记一次寻找Bug的经历-重新理解javascript原型和程序员瓶颈

记一次寻找Bug的经历 今天下午的时候,同事说发现了一个问题.Ext4做好页面,重新单击菜单动态加载一次,树就消失了.于是,我帮忙看了一下,一开始没认为是什么大问题.但是越调发现越不对.到快下班...

架构梦想
2014/04/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

百度贴吧发送gif图片的限制

百度贴吧中不可以发送超过500k的gif图片,同时尺寸不能超过700个像素。

gugudu
21分钟前
1
0
eclipse中查找所有汉字

今天遇到需要对中文翻译为英文的情况,需要查找一下项目中出现的所有汉字。我们可以使用快捷键Ctrl+H,在搜索一栏输入:[^\x00-\xff],记得勾选正则表达式。 备注: [\x00-\xff] 是 0 - 255的...

hengbao5
23分钟前
2
0
HBase常用操作命令

HBase – Hadoop Database,是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。 HBase是Google Bigtable的开源实现,...

飓风2000
27分钟前
2
0
天创恒达TC TC6C0更新固件包

天创恒达TC TC6C0 升级完 登录密码 admin、000000

yizhichao
29分钟前
2
0
阿里云总裁胡晓明:“这些新杭州故事,明天将会在更多城市发生”

摘要: 9月19日,2018杭州·云栖大会现场,杭州城市大脑2.0正式发布,管辖范围扩大28倍,覆盖面积增至420平方公里,相当于65个西湖大小。 ET城市大脑等数字化城市解决方案,掀开了“杭州故事...

阿里云官方博客
30分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部