标签:
有了良好的基础,才能在其上创造有价值的东西。
回顾一下以往自己javascript应用的开发经历,似乎很少去思考和总结js的运行机制。现在我就来整理整理
1. 以《编译原理》的一段话开头:
传统的编译型语言,编译的过程是:词法分析、语法分析、语义检查、代码优化和字节生成;
解释型语言,通过词法分析和语法分析后得到语法树,然后就可以开始解释执行了。
词法分析是将字符流转换为记号流。词法结构是一门语言的基础,词法分析又是另一个领域了。
eg:
自然语言翻译来看,词法分析是一对一的硬性翻译,还很难理解,进一步翻译---》语法分析
语法分析 --》 语法树 后可能还有模糊不清的地方 --》 语义检查( 对于传统强类型语言来讲,语义检查的主要部分是类型检查:
函数的实参和形参的类型是否匹配 )
任何语言都有编译过程,只是解释型语言没有编译成二进制代码
2. js的作用域机制
词法作用域(静态作用域(with和eval除外)):js变量的作用域是在定义时决定而不是执行时决定。
js引擎在执行每个函数实例时,都会创建一个执行环境。执行环境中包含一个调用对象(call object),
调用对象是一个scriptObject结构,用来保存内部变量表varDecls、内嵌函数表funDecls、父级引用列表upvalue等语法分析结构(varDecls和funDecls等信息是在语法分析阶段就已经得到,并保存在语法树中的。函数实例执行时,会将这些信息从语法树复制到scriptObject)
词法作用域是js的作用域机制,它的实现方法就是作用域链。作用域链是一个name lookup机制,首先在当前执行环境的scriptObject中寻找,没找到,则顺着upvalue到父级scriptObject中寻找,一直lookup到全局调用对象。
当一个函数实例执行时,会创建或关联到一个闭包。scriptObject用来静态保存与函数相关的变量表,闭包则在执行期动态保存这些变量表及其运行值。
函数实例在活动引用为空后会自动销毁,闭包则要等要数据引用为空后,由JS引擎回收(有些情况下不会自动回收,就导致了内存泄漏)。
现在可以解释一下“预解析”:step2的语法分析阶段完成,并存储在语法树中。当执行到函数实例时,会将varDelcs和funcDecls从语法树中复制到执行环境的scriptObject上。
未定义变量意味着在scriptObject的变量表中找不到,JS引擎会沿着scriptObject的upvalue往上寻找,如果都没找到,对于写操作i = 1; 最后就会等价为 window.i = 1; 给window对象新增了一个属性。对于读操作,如果一直追溯到全局执行环境的scriptObject上都找不到,就会产生运行期错误。
标签:
原文地址:http://www.cnblogs.com/youlanlan/p/4789895.html