九、作用域和预解析
第一部分:作用域
(一)作用域导读
(二)JS作用域和变量
-
作用域
通常来说,一段代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性代码范围就是这个名字的作用域.作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突.
全局作用域:整个script标签中都可以用,或者是一个单独的js文件
局部作用域:在函数内部就是局部作用域.
局部作用域定义的变量,名字可以与全局变量重复,不会引发冲突,优先使用局部变量.
根据作用域的不同,变量可分为两种,全局变量和局部变量.
-
全局变量和局部变量
在全局直接声明的变量是全局变量.
全局变量在代码任何位置都可以使用.
注意:在函数内部没有声明直接赋值的变量也是全局变量
函数的形参是局部变量.
-
从执行效率看全局变量和局部变量
全局变量只有浏览器关闭的时候才会销毁,比较占内存资源
局部变量当程序执行完毕就会销毁,比较节约内存资源.
-
JS没有块级作用域
在ES6以前没有块级作用域,ES6以后才有.
块级作用域:
if(xxx){ var num=10; } for(xxx){ var num=10; }
在JS中,这两种语句里定义的变量视为全局变量.
(三)作用域链
只要是代码,就至少有一个作用域.
写在函数内部的是局部作用域.而如果函数中还有函数,那么在这个作用域中就又可以诞生出一个作用域.
函数中可以定义函数:
var num=10; function fn(){ //外部函数 var num=20; function fun(){ //内部函数 console.log(num); //输出结果为20 } fun(); }
外面的叫外部函数,里面的叫内部函数
根据在内部函数可以访问外部函数作用域这种机制,用链式查找决定那些数据能被内部函数访问,就称为作用域链.
简单来说:就近原则
(四)作用域链案例
var num=456; function f1(){ //外部函数 var num=123; function f2(){ //内部函数 console.log(num); //输出结果为20 } fun(); } fn();
作用域链:
小技巧:站在目标出发,一层一层往外找,找到的第一个目标,就是答案.
第二部分 预解析
(一)预解析导读
(二)预解析
JS代码是通过浏览器中的UJS解析器来执行的.JS解析器在运行JS代码的时候分两步:预解析和代码执行
-
预解析,JS引擎会把js里面所有的var还有function提升到当前作用域的最前面.
-
代码执行,按照代码书写顺序从上向下执行.
预解析分为变量预解析(变量提升)和函数预解析(函数提升)
-
变量提升:把所有的变量声明提升到当前的作用域最前面,只提升变量声明,不提升赋值操作.
console.log(num); var num=10;
相当于是:
var num; console.log(num); var num=10;
而:
fun(); var fun=fuction(){ console.log(22); }
相当于以下代码:
var fun; fun(); fun=fuction(){ console.log(22); }
调用的fun还是变量,而不是函数,所以会报错.
-
函数提升:把函数声明提升到当前作用域的最前面.不调用函数.
只适用于直接定义的函数,不适用于函数表达式.
(三)预解析案例
案例1:
var num=10; fun(); function fun(){ console.log(num); var num=20; }
问,输出的值是多少?
相当于执行了下面的操作:
var num; num=10; fun(); function fun(){ var num; console.log(num); num=20; }
所以输出为:undefined.
案例2:
var num=10; function fn(){ console.log(num); var num=20; console.log(num); } fn();
输出结果为多少?
很简单,undefined 20.
案例3:
f1(); console.log(c); console.log(b); console.log(a); function f1(){ var a=b=c=9; //相当于: var a=9; b=9; c=9; b和c前没有var console.log(a); console.log(b); console.log(c); }
输出结果为多少?
预解析:
function f1(){ var a; a=9; b=9; c=9; //这里的b和c直接赋值,没有声明,当全局变量看!!! console.log(a); console.log(b); console.log(c); } f1(); console.log(c); console.log(b); console.log(a);
所以结果为:9 9 9 9 9 报错.