JavaScript 的全局变量与局部变量
首先说一下编程语言中全局变量与局部变量的区别。全部变量存储在静态区中,程序运行开始时为其分配内存,程序运行结束后该内存才被释放。局部变量存储在栈中,随程序调用被申请和释放。
在 Javascript 当中,变量的作用域是根据方法块来划分的,即以 function 的一对大括号 { }
来划分。而 for、while、if 块并不是作用域的划分标准。全局变量与局部变量在程序中的区别就在于作用域的不同。
一般情况,如果在任何函数定义之外声明了一个变量,则该变量为全局变量,且该变量的值在整个持续范围内都可以访问和修改;如果在函数定义内声明了一个变量,则该变量为局部变量,每次执行该函数时都会创建和破坏该变量,且它不能被该函数外的任何事物访问。
变量定义
变量都应该先申明再使用,JavaScript 用关键字 var 声明变量:
var varname;
只声明不赋值的变量则是空的,JavaScript 认为它是未定义的(underfined)。也就是说未使用值来声明的变量,其值实际上是 undefined。对一个未申明的变量进行引用则会导致脚本出错而停止运行,即出现ReferenceError: XXX is not defined
。
当然,可以在声明变量的同时对变量进行赋值:
var name=”Huoty”;
变量申明也可以不用 var,而是直接采用赋值的方式:
a = 10;
这样申明的变量默认是全局变量,但不建议这样做。虽然它是全局变量,但也受作用的限制,这似乎很绕,我们来看一个例子:
<body>
<button type="button" onclick="getclick()">Click Me!</button>
</body>
<script>
function getclick()
{
a = 10;
alert(a);
}
console.log(a);
</script>
这段代码会有 ReferenceError: a is not defined
的错误,原因是在全局作用域中 a 未申明,但 a 确实为全局变量。原因是函数 getclick 只在按钮被单击时调用,而 a 也在此时被定义,console.log(a) 则是在脚本被加载时就调用,a 未来得及定义。而从表面上看这段代码是没有问题的,所以建议统一使用 var 来定义变量,需要全局变量时只需在函数外定义即可。个人认为这是 JavaScript 在设计上的一个缺点,容易让人混淆。如果 getclick 不是由点击事件触发,则这段代码就不会除错,如下所示:
function getclick()
{
a = 10;
alert(a);
}
getclick();
console.log(a);
我们再来看另外一个例子:
var a = 1;
document.write(a + '<br>');
function demo()
{
document.write(a + '<br>');
var a = 3;
}
demo();
程序输出 1 和 undefined,是不是很奇怪,应该输出 1 和 1 才对。这又涉及到另外一个问题,当全局变量跟局部变量重名时,局部变量会覆盖掉全局变量。同时,Javascript 在执行前会对整个脚本文件的声明部分做完整分析(包括局部变量),从而确定实变量的作用域。在这段代码中,函数 demo 中有一句 var a = 3;
,Javascript 在做分析时,认为 a 在函数 demo 中是局部变量,而在执行语句 document.write(a + '<br>');
时,变量还未来得及定义就被引用,所以是 undefined。
如果在局部作用域中要引用全局作用域的值,则用 window.globalVariableName 方式来访问,window 是一个全局对象。例如:
var a = 1;
function demo()
{
var a = 3;
document.write(a + '<br>');
document.write(window.a + '<br>');
}
demo();
document.write(a);
输出结果是: 3 1 1
显式声明与隐式声明
显式声明与隐式声明是针对全局变量而言的。之前有提到变量的申明可以用 var 关键字,也可以不用。使用 var(关键字) + 变量名(标识符)的方式在 function 外部声明,则为全局变量的显示申明;没有使用var,直接给标识符赋值,这样会隐式的声明一个全局变量,即使该语句是在一个 function 内,当该 function 被执行后也会变成全局变量,仅当该 function 被执行时。
全局变量还可以使用 window 全局对象来申明,全局对象的属性对应也是全局变量,例如:
window.a = 5;
全局变量优缺点
优点:
- 可以减少变量的个数,减少由于实际参数和形式参数的数据传递带来的时间消耗。
缺点:
-
全局变量保存在静态存贮区,程序开始运行时为其分配内存,程序结束释放该内存。与局部变量的动态分配、动态释放相比,生存期比较长,因此过多的全局变量会占用较多的内存单元。
-
全局变量破坏了函数的封装性能。函数象一个黑匣子,一般是通过函数参数和返回值进行输入输出,函数内部实现相对独立。但函数中如果使用了全局变量,那么函数体内的语句就可以绕过函数参数和返回值进行存取,这种情况破坏了函数的独立性,使函数对全局变量产生依赖。同时,也降低了该函数的可移植性。
-
全局变量使函数的代码可读性降低。由于多个函数都可能使用全局变量,函数执行时全局变量的值可能随时发生变化,对于程序的查错和调试都非常不利。
因此,在不是很必要的时候,不建议使用全局变量。
要点总结
-
(1)JavaScript 的变量作用域是根据方法块来划分的(也就是说以function的一对大括号{}来划分)。切记,是function块,而for、while、if块并不是作用域的划分标准。
-
(2)JavaScript 在执行前会对整个脚本文件的声明部分做完整分析(包括局部变量),从而确定变量的作用域。
-
(3)当全局变量跟局部变量重名时,局部变量的作用域会覆盖掉全局变量的作用域。当离开局部变量的作用域后,又重回到全局变量的作用域。而当全局变量遇上局部变量时,用 window.globalVariableName 访问。