浏览器在阅读js代码的时候,分几步执行
1:预解析
“找一些东西”:var function参数
(1)当遇见有var定义的变量时,不管是声明变量还是声明加上给变量赋值,在预解析的时候,就是在正式运行代码之前,都要提前赋一个值:undefined。
var a=1;
预解析时就是 a=undefined
(2)当遇见函数时,浏览器不会管你函数里面是什么东西,预解析时,直接搬整个函数块。
function f1(){
alert(1);
}
预解析的时候就是 function f1(){alert(1);}
(这个也算是浏览器偷个懒,因为有可能函数里面是很复杂的东西,要是在一开始就解析里面全部东西,就会使在某些情况下浪费时间。)
2:逐行解读代码
解读是表达式的代码:=+-*/%++ – !参数……
表达式是可以改变预解析的值的
解读是函数调用的代码,当遇见函数调用时。在被调用的函数内部也会出现一次预解析,因为在全局预解析的时候函数内部是没有解析的,这里的预解析和上面提到的一样,在预解析完后,又是一样的逐行解读代码。还要注意的是,如果一个变量在函熟内预解析时并没有找到,那么就会跳出函数在上一级里面找。
下面用具体的例子来说说预解析!
(1):
var a=1; //1 预解析时,解析为undefined,这是全局变量
function f1(){ //2 预解析函数,函数就是一个整体保存
alert(a); //5 undefined 这里的a是局部变量,预解析时为undefined
var a=2; //4 预解析时,解析为undefined,这是局部变量
}
f1(); //3 函数调用时。会返回函数内部预解析
alert(a); //6 逐行解读代码,这里的a是全局变量,为1
要注意的是
alert(a); //undefined
var a=2;
alert(a); //2
浏览器先从上到下预解析,当看见var时就把a变为undefined,这个时候没有其他的预解析关键词就开始逐行解读代码,到 alert(a); 时,a的值是undefined,所以弹出undefined,在读到 var a=2;把2赋给a,这时a的值就是2,所以第二个 alert(a);的值就是2。
(2):
var a=1; //1 预解析时,解析为undefined,逐行解读代码的时候为1
function f1(){ //2 预解析函数,函数就是一个整体保存
alert(a); //4 函数里面没有var定义变量,就返回上一级找,上一级有a=1,这里的a就是1
a = 2; //5 这是一个表达式,修改了a的值,这里修改的是全局a的值
}
f1(); //3 函数调用时。会返回函数内部预解析
alert(a); //6 由于全局变量a的值在函数内部被修改 所以这里是 2
注意这里面函数内改变了全局变量,也就是说,当函数内没有定义变量时,就会顺着函数返回上一级域找,也就是跳出函数找,找得到就按照找到的值来运行,找不到浏览器就会报错,如果函数内还有一些改变变量值的表达式,则就会改变上一级域中的值,如上面例子的第五步。
(3)
var a=1; //1 预解析时,解析为undefined,逐行解读代码的时候为1
function f1(a){ //2 预解析函数,函数就是一个整体保存 其中参数a实际上是 var a,局部变量
alert(a); //4 参数是var a;那么预解析就是undefined,所以弹出undefined
a=2; //5 赋值给a a=5
}
f1(); //3 函数调用时。会返回函数内部预解析
alert(a); //6 这里的a是全局变量 没有变还是1
(4):
var a=1;
function f1(a){ //这里的参数是 var a,要是函数调用时传了参数,这里就是var a=参数;参数为1,所以这里的a=1
alert(a); //1
a=2; //赋值给局部变量 a=2
}
f1(a); //这里的参数就是全局变量,a=1
alert(a); //这是全局变量 没有改变 为 1
还有几种其他的情况,比如
(1)
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
a(); //报错,此时的a是3一个数,不是函数了。
这个例子中,有很多个重名的变量和函数,预解析的原则是从上到下,遇见重名的变量和函数时,保留函数,遇见两个重名的函数时,保留下面那个函数。
(2)
<script>
alert(a); //报错
</script>
<script>
var a=1;
</script>
每个<script> </script>
之间就是一个全局的域,浏览器在解析的时候会自上而下把每个域解析完并且执行完才会解析另外一个script域
<script>
var a=1;
</script>
<script>
alert(a); // 1
</script>
这样换个位置是可以的,上一个域中解析出的a=1会存放在内存当中,下面的域是可以用的。
(3)
要是我们想把函数内的变量值拿出来,这时我们可以这么做
function f1(){
var a='大龙虾';
}
我们想把里面的“大龙虾”拿出来,怎么办?我们上面说过局部变量时可以改变全局变量的,那我们顺着这思路这样来做
var str='';
function f1(){
var a='大龙虾';
str=a;
}
f1();
alert(str); // 弹出大龙虾
(4)
还有一种获取函数内值的方法。或者说是情况
function f2(){
var a='大龙虾';
}
f2();
function f3(){
alert(a); //我们是想在这里弹出 “大龙虾”,但是现在不会弹出
}
f3();
这个就是两个函数之间参数值相互用的情况,但是上面的代码是弹不出“大龙虾”的。因为参数不一样,那我们还是有办法的,如下
function f2(){
var a='大龙虾';
f3(a);
}
f2();
function f3(a){
alert(a); //弹出 “大龙虾”
}
这里利用的是传参,我们在f2()当中放个间谍,这个间谍就是f3(a),然后他把信息偷出来,自己一伙儿大摇大摆的用,^_^!
最后大家还是要注意不是有大括号就是一个域,像if for语句这样也有大括号的,但他们不是一个作用域,但是大家不要在if for语句里面去声明函数,因为火狐不能预解析if for 里面声明的函数,会报错,所以为了浏览器都能解析,所以都把这些代码在外面声明,反正都是全局变量。