JavaScript中全局变量的问题

全局变量的问题在于,你的JavaScript应用程序和web页面上的所有代码都共享了这些全局变量,他们住在同一个全局命名空间,所以当程序的两个不同部分定义同名但不同作用的全局变量的时候,命名冲突在所难免。

web页面包含不是该页面开发者所写的代码也是比较常见的,例如:

  • 第三方的JavaScript库

  • 广告方的脚本代码

  • 第三方用户跟踪和分析脚本代码

  • 不同类型的小组件,标志和按钮

比方说,该第三方脚本定义了一个全局变量,叫做result;接着,在你的函数中也定义一个名为result的全局变量。其结果就是后面的变量覆盖前面的,第三方脚本就一下子被覆盖了。

因此,要想和其他脚本成为好邻居的话,尽可能少的使用全局变量是很重要的。在后面提到的一些减少全局变量的策略,例如命名空间模式或是函数立即自动执行,但是要想让全局变量少最重要的还是始终使用var来声明变量。

由于JavaScript的两个特征,不自觉地创建出全局变量是出乎意料的容易。首先,你可以甚至不需要声明就可以使用变量;第二,JavaScript有隐含的全局概念,意味着你不声明的任何变量都会成为一个全局对象属性。参考下面的代码:

function sum(x, y) {   // 不推荐写法: 隐式全局变量    result = x + y;   return result;}

此段代码中的result没有声明。代码照样运作正常,但在调用函数后你最后的结果就多一个全局命名空间,这可以是一个问题的根源。

经验法则是始终使用var声明变量,正如改进版的sum()函数所演示的:

function sum(x, y) {   var result = x + y;   return result;}

另一个创建隐式全局变量的反例就是使用任务链进行部分var声明。下面的片段中,a是本地变量但是b却是全局变量,这可能不是你希望发生的:

// 反例,勿使用 function foo() {   var a = b = 0;   // ...}

b没有通过var声明所以,无意中多了个全局变量。如果你已经准备好声明变量,使用链分配是比较好的做法,不会产生任何意料之外的全局变量,如:

function foo() {   var a, b;   // ... a = b = 0; // 两个均局部变量}

隐式全局变量(没有var声明的变量)和明确定义的全局变量间有些小的差异,就是通过delete操作符让变量未定义的能力。

  • 通过var创建的全局变量(任何函数之外的程序中创建)是不能被删除的。

  • 无var创建的隐式全局变量(无视是否在函数中创建)是能被删除的。

这表明,在技术上,隐式全局变量并不是真正的全局变量,但它们是全局对象的属性。属性是可以通过delete操作符删除的,而变量是不能的:

// 定义三个全局变量 
var global_var = 1; 
global_novar = 2; // 反面教材 
(function () { 
  global_fromfunc = 3; // 反面教材 
}()); 
// 试图删除 
delete global_var; // false 
delete global_novar; // true 
delete global_fromfunc; // true 
// 测试该删除 
typeof global_var; // "number" 
typeof global_novar; // "undefined" 
typeof global_fromfunc; // "undefined"