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); //17 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 undefined11 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 111 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 undefined8 alert(a); //19 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