Javascript预解析相关一则
先来看一段代码:
alert("a" in window); /*true - 1*/ if( false ){ var a = 1; } alert("b" in window); /*false - 2*/ if( false ){ b = 1; } alert("b" in window); /*false - 3*/ alert("c" in window); /*false - 4*/ if( true ){ c = 1; } alert("c" in window); /*true - 5*/
以上代码片段是在全局作用域下定义的,对于第一个例子,Javascript在预解析的时候已经将变量a的声明添加到了活动对象中(具体可参考Javascript的“预解析),于是在运行时 “a” in window 为true。
然后第二个例子的结果是false,也就是说变量”b”在预解析的过程中并没有被放置在当前环境的活动对象中,原因在于没有使用var来定义变量”b”。对于使用了var定义的变量,预解析时可以明确的知道这是当前作用域的“本地”变量,因此可以准确无误的将变量添加到活动对象中,而那些没有使用var定义的变量则需要在运行时去处理。示例中的2 – 5句正好验证了没有使用var定义的变量需要在运行时进行处理。
在Answering Baranovskiy’s JavaScript quiz一文中给出的前3个问题均与预解析相关,如下:
if (!("a" in window)) { var a = 1; } alert(a);/*undefined*/
预解析时已经将变量a添加到window上,因此!(”a” in window)为false,导致运行时a没有被赋值,所以a的值为undefined。
var a = 1, b = function a(x) { x && a(--x); }; alert(a);/*1*/
这个在所有浏览器下都输出1,预解析时,第一行定义的变量a被添加到了window对象中,此时它的值为undefined,解析到第二行时,变量b也被添加到window对象中,其值也为undefined。同时,在IE下,后面的函数表达式也会被当做一个函数定义来处理,即相当于
var a = 1; var b = function (x){ x && a(—x); }; function a(x) { /*在IE下会被当做函数定义处理*/ x && a(--x); } alert(a);/*1*/
当解析过程完成后,window对象中的变量a的引用是一个函数定义(仅限于IE),而到了运行时给变量赋值的时候,执行了以下3个动作:
1. 给变量a赋值为1(覆盖了原先a上面的函数定义)
2. 给变量b赋值为函数表达式
3. alert(a)
因此a的值为1。
function a(x) { return x * 2; } var a; alert(a);/*函数代码*/
预解析时,完成了函数a的定义,即在window对象上添加变量a,并赋值为函数定义。之后遇到”var a;”,由于当前作用域已经有变量a,因此不需要做什么工作。在运行时,由于并没有给变量a赋值,因此原来的函数定义并没有覆盖,因此最终变量a是一个函数。如果将”var a;”改为”var a=1;”,则最终a的值为1。
You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.
这篇文章把权威指南第八章 call object 的内容与《Answering Baranovskiy’s JavaScript quiz》中“变量声明会上升”部分融会贯通连为整体了。
非常感谢,解开了我很多迷雾。