在学习JavaScript的变量作用域之前,我们应当明确几点:
a、JavaScript的变量作用域是基于其特有的作用域链的。
b、JavaScript没有块级作用域。
c、函数中声明的变量在整个函数中都有定义。
<script> var x = 1; function outer() { var y = 2; function inner() { var z = 4; alert(x); } inner(); } outer(); </script>
alert(x)这句代码,JavaScript首先在inner函数中查找是否定义了变量x,如果定义了则使用inner函数中的x变量;
如果inner函数中没有定义x变量,JavaScript则会继续在rainman函数中查找是否定义了x变量,在这段代码中outer函数体内没有定义x变量,则JavaScript引擎会继续向上(全局对象)查找是否定义了x;
在全局对象中我们定义了x = 1,因此最终结果会弹出‘1‘。
作用域链:JavaScript需要查询一个变量x时,首先会查找作用域链的第一个对象,如果以第一个对象没有定义x变量,JavaScript会继续查找有没有定义x变量,如果第二个对象没有定义则会继续查找,以此类推。
上面的代码涉及到了三个作用域链对象,依次是:inner、outer、window。
2、函数体内部,局部变量的优先级比同名的全局变量高。
<script> var x = 1; function check() { var x = 100; //定义局部变量x alert(x); //这里会弹出 100 } check(); alert(x); //这里会弹出1 </script>
3、JavaScript没有块级作用域。
这一点也是JavaScript相比其它语言较灵活的部分。
仔细观察下面的代码,你会发现变量a、b、c作用域是相同的,他们在整个inner函数体内都是全局的。
<script> function inner() { var a = 0; if (1) { var b = 0; for (var c = 0; c < 3; c++) { alert(c); // 分别弹出 0 1 2 } alert(c); //弹出3 } alert(a); //弹出0 alert(c); //弹出3 } inner(); alert(c); //不弹值 ,如果将var c = 0 中 var 去掉,则会弹出 3 </script>
对于有块级作用域的语言来说,for语句中定义并初始化的变量i在循环外是无法访问的,而在javascript中,for语句中定义的变量c在循环结束后,依旧会存在于循环外部的执行环境(作用域)中,在这里c的作用域是全局环境。具体来说就是:使用var关键字声明变量时,这个变量会自动添加到距离最近的可用环境中。对于函数而言,这个最近的环境就是函数的局部环境。
如果变量在未经声明的情况下被初始化,则该变量会被自动添加到全局环境。
不过有时候的确很需要块级作用域来解决一些问题,这时候我们就可以使用匿名函数来模仿块级作用域。
匿名函数就是没有名字的函数,有时候也被称为拉姆达(lamda)函数。形式如下:
(function(){
//块级作用域
})();
以上代码的意思是:首先定义并立即调用一个匿名函数。将函数声明包含在圆括号中,表示它实际上是一个函数表达式。而紧随其后的另一对圆括号表示立即调用这个函数。
当匿名函数执行完毕,其作用域链立即销毁,从而可以减少闭包占用资源问题。
4、函数中声明的变量在整个函数中都有定义。
<script> function outer() { var x = 1; function inner() { x = 100; } inner(); alert(x); //弹出 100 } outer(); </script>
上面代码说明了,变量 x 在整个 outer 函数体内都可以使用,并可以重新赋值。
由于这条规则,会产生“匪夷所思”的结果,观察下面的代码。
<script> var x = 1; function inner() { alert(x); //弹出 ‘undefined‘,而不是1 var x = 2; alert(x); //弹出 2 } inner(); </script>
这是由于在函数 inner 内局部变量 x 在整个函数体内都有定义 var x= 2,进行了声明 ) , 所以在整个 inner 函数体内隐藏了同名的全局变量 x 。
这里之所以会弹出 ‘undefined‘ 是因为,第一个执行 alert(x) 时,局部变量 x 仍未被初始化。
所以上面的 inner 函数等同于下面的函数。
<script> function inner() { var x; alert(x); x = 2; alert(x); } </script>
5、未使用var关键字定义的变量都是全局变量。
这也是JavaScript新手常见的错误,无意之中留下的许多全局变量。
<script> function inner() { x = 100; // 声明了全局变量x并进行赋值 } inner(); alert(x); //会弹出100 </script>
6、全局变量都是window对象的属性
<script> var x = 100; alert(window.x); //弹出100 alert(x); </script>
等同于下面的代码
<script> window.x = 100; alert( window.x ); alert(x) </script>