涉及到JavaScript运行机制和函数的作用域去深入了解变量。
全局变量与局部变量
首先要了解变量的生存期:
全局变量:从定义开始一直到本程序结束为止。
局部变量:在函数中定义,有效范围在函数之内,当函数结束后,局部变量生存期也就结束了。
有一点时:当给未声明的变量赋值,JavaScript 会自动用该变量名创建一个全局变量。
ps 一个小例子
<script>
function a(){
i=1;
}
function b(){
alert(i);
}
b();
</script>
执行结果 i is not defined
解释:函数 a 没有被调用,相当于声明了 i ,但是没有给 i 赋予任何值。这里 i 为全局变量。
JS的解析过程分为两个阶段:预编译期(预处理)与执行期
预编译期:对所有声明的变量和函数进行处理。声明的函数前置;变量进行声明但未进行初始化(即只是分配了内存)即:
变量:查找通过var 声明的变量,马上作为window一个属性并初始化为 undefined
函数:声明的函数前置
以下为两个例子:
<script>
alert(a);
var a = 1 ;
</script>
结果输出 undefined
<script>
alert(a);
a = 1 ;
</script>
结果 报错,a is not defined。这段代码被解析时并未发现有var关键字,因此执行到alert(a)时,就等于执行alert(window.a),而window对象尚没有a属性,当然就报错了。
在看个案例
<script>
var a = 10;
var b = true;
function test() {
alert(a); //undefined
alert(b); //true
var a = 200;
b = false;
alert(b); //false
alert(a / 2); //100
}
test();
alert(a); //10
alert(b); //false
</script>
执行过程
首先,js 要预编译,预编译过程中为每个变量分配了内存。
第二步,按照代码的顺序执行代码:
var a = 10:为全局变量a 赋值
var b = true:为全局变量 b 赋值
test(){}:进入函数test ,则由于局部变量会在函数内部覆盖同名的全局变量,故此时的状态便是a 未赋值,b的值为true
var a = 200: 将位于函数test 中的局部变量a 赋值200,覆盖同名的全局变量
b = false:将位于函数test中的全局变量b 赋值false,覆盖同名的全局变量
test{} 函数执行结束:局部变量a 生存期结束,全局变量 b 值为 false
解释函数内部 alert(a) 为什么值为 undefined
预编译阶段:获得已声明的变量a、b 和声明函数test 作用域以及函数内部 a的作用域。
程序执行到第六行代码时:立即调用内围作用域的a,这时它还没有来得及赋值呢!不过它已经声明过了,因此默认为其赋值为 undefined(在预编译阶段,见图),于是 alert 为 undefined。
程序执行到第七行代码时:就调用 b 时,发现 test 的作用域内没有 b,则往外寻,于是 alert 为 true。