“js解析器”执行的过程至少2步:
1、"找一些东西":比如 var 、function、参数
2、逐行解读代码
例:
alert(a);
var a=1;
function fn1(){
alert(2);
}
解析过程:
1、JS的预解析过程 原则:遇到重名的:只留一个(变量和函数重名了,就只留下函数。无论变量在上还是函数在上,与上下是没关系的,跟有值没值有关系。因为变量=undefined,函数=整个函数块,相比之下有具体值的级别更大)
找到var关键字,然后定义其变量名等于undefined,不会管后面的值(在"JS解析器"执行的过程中,所有的变量都等于未定义) 如:a=undefined
找到function关键字,然后用其函数名等于其整个函数块。(所有的函数,在正式运行代码之前,都提前赋了一个值,这个值为整个函数块) 如:fn1=function fn1(){alert(2);}
这个过程遵循"从上往下,从左往右"的顺序执行。
当执行一句完毕后,到仓库中查找是否有这个"东西"(变量、函数等)。如果有则弹出其一开始在仓库的值(使用alert方法)
遇到表达式(=+ - * / % ++ -- ! 参数……等即能改变值的东西)
简单来说,找var 、function、参数,并将变量赋值为undefined、函数名=整个函数,然后将他们存储在仓库中,在进行逐行解读代码的时候,在仓库中提取或修改
练习:
解析过程
1、找关键字(var、function、参数)
找到37行的"var a",执行过程:a=undefined
找到39行的"function a(){alert(2);}",执行过程:a=function a(){alert(2);}
因为仓库里有重名的a,所以要比较优先级,值为函数的大于值为未定义,所以执行过程为a=function a(){alert(2);}
找到41行的"var a ",执行过程:a=undefined
因为仓库里有重名的a,所以要比较优先级,值为函数的大于值为未定义,所以执行过程为a=function a(){alert(2);}
找到43行的"function (){alert(4);}",执行过程:a=function (){alert(4);}
因为仓库里有重名的a,所以要比较优先级,值同为函数则比较先后,后面的覆盖前面的,所以执行过程为a=function a(){alert(4);}
2、逐行解析:
从上往下,从左到右依次执行代码。从36行开始,a的一开始值为function a(){alert(4);}
执行37行时,修改仓库中a的值,则变为1
执行39行时,并不影响a的值,所以a的值还是1
后面亦是如此
一个页面两个script标签,浏览器遇到script标签会用"js解析器"来解析,只有解析完第一个script标签的内容后在执行下一个script标签内的内容,所以下面alert(a); 会报错 a is no defined。
这就是当引用别人写的jQuery库时,在对其修改
var a = 1;
function fn1(){
alert(a); //undefined
var a = 2;
}
fn1();
alert(a); //1
解析过程:
1、预解析:
a=undefined;
fn1=function fn1(){ alert(a); var a = 2;}
2、逐行解析;
a=1
遇到函数调用fn1() --函数也是一个局部的域,只要是一个域就会发生预解析和逐行解读代码。相当于其有一个小的仓库。可以理解为1个大仓库包含着1个小仓库,大仓库里的a和小仓库里的a是不同的世界,互不影响。函数调用属于表达式
函数里的预解析:
a=undefined; //这里的a是局部的,外面的是全局的,两者没关系
函数里的逐行解析:
执行函数里的alert(a); 先找局部仓库里的a,所以弹出undefined
在执行函数里的var a=2; 所以局部里的a=2,并没有影响全局中的a=1
函数执行完毕后会有垃圾回收机制等
函数调用完毕后,继续全局的逐行解析
var a = 1;
function fn1(){
alert(a); // 1
a = 2; //注意这里没用var声明
}
fn1();
alert(a); // 2
函数里的预解析过程为空,执行函数里的逐行解析代码:当执行到alert(a);没找到a,会顺着函数的作用域跳到上一级(从子级作用域返回到父级作用域的过程叫作用域链,由里到外找)。执行到"a=2"时,发现小仓库里没有a,则由里到外找,找到其父级有a,则修改a的值为2
所以,加var与不加var的区别体现出来了。不加var,会修改全局变量的值
var a = 1;
function fn1(a){
alert(a); // undefined
a = 2;
}
fn1();
alert(a); // 1
参数本质就是一个局部变量。跟上面的其中一种情况(如下)很类似
函数预解析时没有发现var、function ,却发现了参数,所以a=undefined。
然后逐行解读代码,当读到"alert(a);",执行结果为undefined
当读到"a=2;",它会就近找小仓库里有没有a,执行结果为a=2,全局的a还是1不影响
var a = 1;
function fn1(){
alert(a); // undefined
var a = 2;
}
fn1();
alert(a); // 1