作用域:简单来说就是在什么样的空间范围内,对数据进行读写操作
域:就是空间、范围、区域
作用:读和写
在浏览器中,有专门读JS的东西,我们叫js解析器。
js解析器至少分为两步:
1)JS的预解析
2)逐行解读代码
下面通过三个例子来看一下js解析器是如何解析js代码的:
例1:
alert(a);//undefined
var a = 1;
function fn1(){
alert(2);
}
第一步、JS的预解析:
1、首先JS解析器要找一些东西‘var’、‘function’、‘参数’等;
2、代码运行到第一行是alert(a);
没找到‘var’、‘function’等需要找东西,继续往下运行;
3、在第二行找到了‘var’,于是js解释器记住了a,并给a赋值为‘未定义’即:‘a = 未定义’,因为所有变量在正式运行代码之前都提前赋予了一个‘未定义’的值;
4、继续运行代码,根据‘function’找到了fn1 = function fn1(){alert(2);},因为所有的函数在正式运行之前都是整个函数块,它不知道fn1函数里有多少代码,索性全部都拿过来;
总之,只要是变量就是未定义,只要是函数就全部拿过来;
注:1、var a
、function fn1(){alert(2);}
叫做声明;
2、a = 1
叫做表达式,表达式包括‘+、 - 、* 、 / 、 % 、++、 – 、 ! ’等;
第二步、逐行解读代码
1、代码运行到第一行alert(a);
,先到仓库中(预解析的代码)查看有没有a这个变量,一看有a=未定义
,那么就弹出来undefined;
2、运行第二行代码var a = 1;
,看到有一个等号=,就叫做表达式,然后去仓库更改a的值,由原来a=未定义,改为a=1;
例2
alert(a);
a = 1;
首先第一步JS的预解析:没有找到‘var’、‘function’、‘参数’,所以仓库中是空的;
第二步逐行解读代码,读到第一行,看到a,然后到仓库看一下有没有a,一看没有,那么js解释器就不认识这个是什么,然后报错!
例3
alert(a);//function a(){alert(4)}
var a = 1;
alert(a);//1
function a(){alert(2);}
alert(a);//1
var a = 3;
alert(a);//3
function a(){alert(4)}
alert(a);//3
第一步、JS的预解析(找东西)
1、找到第一个‘var’, 然后 a = 未定义
2、找到第一个‘function’,然后 a = function a(){alert(2);}
注意:在预解析中,如果变量和函数重名,那么只留函数,未定义的变量去掉;
即: a = function a(){alert(2);}
3、找到第二个‘var’,然后 a = 未定义
(变量和函数又重名,是未定义,所以去掉)
即: a = function a(){alert(2);}
4、找到第二个‘function’,然后 a = function a(){alert(4)}
(根据优先级,要保留最后出现的函数,所以第一个函数去掉)
即:a = function a(){alert(4)}
最终仓库中保留的是a = function a(){alert(4)}
第二步、逐行解读代码
1、读第一行alert(a);
,先到仓库中找a,一看a = function a(){alert(4)}
,所以弹出function a(){alert(4)}
;
2、读第二行var a = 1;
,看到有一个等号,就是表达式,表达式会去更改预解析仓库中的值,所以仓库中a = function a(){alert(4)}
被改成a = 1
;所以弹出来的是1;
3、读第三行function a(){alert(2);}
,看到function是一个声明,声明不会更改任何东西,并且函数中也没有调用,所以仓库中的值还是1,不会发生任何事情,继续往下解读代码;
4、读第四行alert(a);
又看到a,然后去仓库中找a的值,a=1,所以弹出的是1;
5、读第五行var a = 3;
看到等号是表达式,会更改仓库中的值,所以仓库中 a = 1
变成a = 3;
所以弹出3;
6、读第六行function a(){alert(4)}
,看到function是声明,声明不会更改任何东西,并且函数中也没有调用,所以仓库中的值还是3,不会发生任何事情,继续往下解读代码;
7、因为仓库中的值没有改变,所以弹出3;