首先来看一个例子:
<script type="text/javascript">
var a = 1;
function show() {
console.log(a + 1);
var a = 2;
console.log(a + 1);
}
show();
</script>
其输出结果为:NaN, 3
为什么第一个打印出来的结果是NaN,而不是2呢?
事实上,JS的解析过程分为两个阶段:预编译期(预处理)与执行期。
预编译时JS会对本代码块中所有声明的var变量和函数进行处理,变量会被初始化为undefined,函数则在预编译时就会被解析。
注: 一个script标签即为一个代码块
所以上面一段代码的执行过程是:
1.第一步扫描全局var关键字:
var a; //这个a为全局变量,被初始化为undefined
如果是函数表达式,如var b = function(){},那么b也会被初始化为undefined,等号右边的函数并不会被赋值给b,也不会被解析。
2.第二步扫描function,函数被解析过程如下:
function show() {
var a; //局部变量a被初始化为undefined
console.log(a + 1); //这里引用的是局部变量a,值为undefined,与全局变量a没有半毛钱关系
a = 2; //局部变量a被赋值为2
console.log(a + 1); //2+1
}
3.第三步按顺序执行代码,最终如下:
var a; //全局变量a,被初始化为undefined
function show() {
var a; //局部变量a被初始化为undefined
console.log(a + 1); //这里的a引用的是局部变量,值为undefined
a = 2; //局部变量a被赋值为2
console.log(a + 1); //2+1
}
a = 1; //全局变量a,被赋值为1,不会影响局部变量a的值
show(); //执行show函数
当undefined与number运算时,由于undefined不是number类型,则undefined会被转化为NaN,NaN与number运算时,结果则为NaN。所以第一个打印结果为NaN,第二个打印结果为3。
而如果show函数里没有声明变量a,那么show函数里的a会沿着作用域向上查找,此时a为全局变量,例子如下:
var a = 1;
function show(){
console.log(a + 1);
}
show();
其预编译后为:
var a; //a为全部变量,开始为undefined
function show(){
console.log(a + 1); //引用全局变量a,值为undefined
}
按顺序执行时
a = 1; //--全局变量a的值改变,被赋值为1,则show函数里引用全局变量a也变为1.
show(); //--执行console.log(a + 1),此时的a值已变为1
所以其打印出来的结果是2。
小结一下:JS 在执行前会进行类似”预编译”的操作,而且先预定义变量再预定义函数。而无论是声明的变量还是声明式函数,在执行的时候,都可以覆盖预编译时期的值。这个过程如果发现语法错误,预解析终止。