JavaScript的变量及函数声明提升及预解析
JavaScript引擎在执行的时候,会在相应代码段寻找var声明的变量及函数声明(函数表达式不会提升),把所有变量和函数的声明都提升到当前作用域的最前面。此时变量是未赋值的(undefined),当执行到相应代码段才会赋值,函数是其本身。
并且有以下一些坑:
1.变量声明及函数声明预解析时,变量解析为undefined,函数解析为其本身。预解析时函数声明优先级高于变量声明,函数声明会覆盖变量声明,但不会覆盖变量赋值。如果声明变量的同时初始化或赋值那么变量优先级高于函数。
例1:预解析时,变量解析为undefined,函数解析为其本身,函数声明会覆盖变量声明,故1行输出如下结果。变量赋值覆盖函数,故6.7行结果如下。
1 console.log(a); // function a(){console.log(2); } 2 var a = 1; 3 function a(){ 4 console.log(2); 5 } 6 console.log(a); //1 7 a(); //无法执行
例2:变量a预解析为undefined。fn1运行时沿着作用域链找到8行变量a,但该a在fn1后面故没有赋值,输出undefined。fn同样找到相同未赋值的变量a,输出undefined。
11行根据作用域链输出的是全局变量a。
1 var a =1; 2 function fn(){ 3 console.log(a); 4 function fn1(){ 5 console.log(a); 6 } 7 fn1(); 8 var a =2; 9 } 10 fn(); //undefined undefined 11 console.log(a); //1
2.没有使用var声明的变量为全局变量,预解析时没有使用var声明的同名变量会被隐藏。
例:预解析时8行变量a声明隐藏,fn1及fn运行时沿着作用域链找到全局变量a声明。并且在8行时全局变量a重新赋值。
1 var a =1; 2 function fn(){ 3 console.log(a); 4 function fn1(){ 5 console.log(a); 6 } 7 fn1(); 8 a =2; 9 } 10 fn(); //1 1 11 console.log(a); //2
3.函数形参相当于变量声明。
例:函数fn的形参相当于变量声明var a ,预解析为undefined,故7行运行时沿作用域链找到未赋值的变量a。
1 var a = 1; 2 function fn(a){ 3 alert(5); 4 alert(a); 5 6 } 7 fn(); // 5 undefined 8 alert(a); //1 9 fn(a); //5 1
4.仅仅声明某一个函数,引擎并不会对函数内部的任何变量进行查找或赋值操作。只会对函数内部的语法错误进行检查。
所以循环语句的声明:
1 for(var i=0; i<10; i++) { 2 result[i] = function(){ 3 return i; 4 }
}
我原本以为它是这样的:
1 result[0] = function() { return 0;}; 2 result[1] = function() { return 1;}; 3 result[2] = function() { return 2;}; 4 ......
实际上它是这样的:
1 result[0] = function() { return i;}; 2 result[1] = function() { return i;}; 3 result[2] = function() { return i;}; 4 ......
故下例:
1 function createFunctions() { 2 var result = newArray(); 3 for(var i=0; i<10; i++) { 4 result [i] = function() { 5 return i; 6 } 7 } 8 return result; 9 } 10 var foo = createFunctions(); 11 console.log(foo[0]()); //10