首先我们来看一段代码:
1 <script> 2 console.log(a); 3 var a = 10; 4 </script>
此时运行结果为
为什么会显示undefined呢?这就涉及到了预解析中的变量提升:
1、局部提升(变量) 会把变量声明分成两部分
1) 变量声明 只有这个部分发生了提升,提升至所在作用域的最前面
2) 变量赋值 在原位置;
接下来再看一段代码:
1 <script> 2 foo(); 3 function foo(){ 4 console.log("hello world"); 5 } 6 </script>
此时运行结果为:
我们会发现,声明式的函数,调用在声明之前也是可以访问的。这是因为预解析总的函数提升:
2、整体提升(函数)
整个函数都提升到作用域的最前面
了解了变量提升和函数提升,那么我们来想一下两者谁的优先级更高?
1 <script> 2 console.log(foo); 3 var foo = 10; 4 function foo(){} 5 </script>
显示结果为:结果得到函数而不是变量;
也就是说:函数将变量声明覆盖,说明是先变量提升之后,函数再提升上去将其覆盖。所以,变量提升的优先级高。
总结:
JavaScript 预解析机制 有如下操作:
- 检查你的所有代码有没有语法错误。如果有语法错误,直接终止程序;
- 声明提升:把所有需要和内存交互的行为提前,将所有的内存操作集中在一起提升代码效率。分为局部提升和整体提升2种方式。
并且,声明提升中,局部优先提升,然后整体提升。
声明提升也解释了为什么赋值式的函数 调用在声明前会报错
1 // 2.报错 类型错误 2 foo(); 3 var foo = function(){ 4 console.log("hello"); 5 } 6 // 可以调用 7 // foo();
因为此时为局部提升,先只在内存中定义了 var foo,此时它仍为undefined
以下是一个相关例子
1 <script> 2 foo(); 3 console.log(b); //可以打印,因为b作用域为全局作用域window 4 console.log(c); 5 console.log(a); //不可访问 6 7 function foo(){ 8 var a = 10; //局部变量, var a 解析到函数(作用域)最前面 9 b = c = 7; //变量没有声明,直接赋值变为伪全局变量 10 console.log(a); 11 console.log(b); 12 console.log(c); 13 } 14 </script>