你的位置:首页 > Java教程

[Java教程]Javascript预解析、作用域、作用域链


最近在看js的一些资料,总结一下昨晚看到的js作用域方面的知识,不准确的地方希望留言指正!

先看片段js代码如下:

 

1     < script type="text/javascript" >2 3        console.log(a);4       var a = "hello world!";5 6        console.log(b);7       b = "你好,世界!";8 9     < /script >

View Code

 开始的输出结果很出乎意料,firebug调试输出结果如下:

console.log(a);

输出:undefined

console.log(b);

 ReferenceError: b is not defined
 
 思考:为什么定义变量在后,输出在前,而第一个输出a的地方没有报错,输出了“undefined”,而同样是先输出后定义的b,就报错了呢?

一、浏览器预解析

      浏览器是一个综合的软件,可以打开txt文本、照片、甚至符合格式的视频拖拽进去也能播放,也就是说浏览器支持各种格式的文件解析,具体的原理我们不用知道,需要知道的是,浏览器有一个专门负责解析js语句的东西,我们姑且叫做“js解析器”。

      在js解析器遇到script标记后,就启动解析器解析我们的js代码,这个解析过程中包括很多步骤,比如语法检查、垃圾回收...等等很多,但是其中有2点和我们今天说的作用域有关系,分别是”预加载“和”逐步解析“。

 

 1、js预加载

      当浏览器来执行我的js代码时,并不是一上来就开始一行行的执行我们的代码,而是在执行前有一个“预加载”的操作,预加载做了什么事情呢?

      1> 在当前域中,找到已var 开头的变量,function定义的函数,和参数,并将其提取出来,放到“仓库”中。

      2>将var定义的变量保存起来后,给其赋值为:undefined。需要主意的时候,预加载的时候,不会执行变量后面的表达式,只是单纯的提取出变量名,然后给其值undefined

      3>将function定义的函数名字提取出来,给其赋值为当前函数体,因为js解析器也不知道函数里面有什么东西,所以讲整个函数直接赋值给当前函数名称。

      4>讲参数也提取到“当前域”中,和var 类似,“当前域”这个下面会讲到。

      上面是js预加载做的事情,简单的说,在当前域中(先可以理解为script中的代码)找到var funciton 和参数这三样东西,然后提取出来放到仓库中,第一步完成。

2、逐步解析

 当js预加载完成后,开始执行第二步,逐步解析,通俗的说也就是一行一行的读取代码。我们已第一个代码片段为列子说明。

当预解析后,找到了var定义的变量,只有a是var定义,就把a放在仓库中,定义为undefined。第一步完成后,执行第二步,逐行执行代码。一上来第一行就是:console.log(a),

当读取到变量a的时候,浏览器就到仓库中去找a,因为经过了预解析,在执行代码前已经把a存起来了,并且赋值为undefined了,所以找打了a并且输出了他的值:undefined。

继续往下,读到了表达式 var a = "hello world!"; 同理,找到仓库中的a,并且赋值,记住表达式可以更改仓库中的值。然后继续往下走,读取b的时候,因为仓库中并没有存到变量b,因为他不是var定义的,所以没有,读取一个没有的变量,当然就报错了。