3.4.4 防止变量冲突
函数的一个很好的优点是,它们可以减少必须编写的程序的数量。我们可能会发现自己在不同的项目上一次又一次地使用一个真正有用的函数。例如,辅助计算运输税和销售税的函数可能对于我们所创建的每个订单都有用,因此,可能会把函数复制到站点上或其他项目中的其他脚本中。
当只是把函数放入一个已经创建的脚本中时,会产生一个潜在的问题。如果脚本使用和函数同样的变量名,会发生什么情况呢?函数会覆盖脚本中的变量吗?或者情况刚好相反?例如:
var message='Outside the function';
function warning(message){
alert(message);
}
warning('Inside the function');//'Inside the function'
alert(message);//'Outside the function'
注意,变量message既出现在函数之外(脚本的第一行代码),也作为函数中的一个参数。参数实际上是在函数调用的时候才会使用数据填充的一个变量。在这个例子中,函数调用warning('Inside the function')给函数传递了一个字符串参数,并且函数把这个字符串存储到message变量中。这看上去似乎message变量有两个版本。那么,在脚本的第一行创建的最初的message变量中的值发生了什么?
你可能会认为存储在message中的最初的值被一个新值覆盖了,这个新值就是字符串“Outside the function”,但实际上不是这样。当运行这段脚本的时候,会看到两个对话框:第一个显示“Inside the function”,而第二个显示“Outside the function”。实际上有两个名为message的变量,但是,它们存在于不同的位置(如图3-8所示)。
图 3-8 函数参数只在函数的内部可见,因此,这个函数的第一行function warning(message)会创建一个名为message的新变量,这个变量只能在函数内部访问。一旦函数结束,这个变量也消失了
JavaScript变量对于在函数内部声明的变量和在函数外部创建的变量区别对待。用编程的术语来说,每个变量都有自己的作用域。函数的作用域就像是包围起函数的一堵墙,墙内部的变量不会被墙外部的其他脚本所看到。当你第一次学习作用域的时候,它确实是一个容易混淆的概念,但是它非常有用。因为函数有自己的作用域,所以不必担心在函数中为参数使用的名字会覆盖在脚本其他部分所使用的变量或与之发生冲突。
到目前为止,我们只是讨论了变量作为参数使用的情况。但是,对于在函数内部创建的但不是用作参数的变量,会怎么样呢?例如:
var message='Outside the function';
function warning(){
var message='Inside the function';
alert(message);
}
warning();//'Inside the function'
alert(message);//'Outside the function'
这段代码创建了message变量两次,在脚本的第一行创建一次,在函数内的第一行再创建一次。这种情况和使用它作为参数的情况相同,只不过在函数中输入了var message,我们在函数的作用域内创建了一个新的变量。这种类型的变量叫做局部变量(local variable),既然它只在函数的围墙之内可见,主脚本和其他函数是不能看到或访问这个变量的。
然而,在脚本的主要部分(函数之外)创建的变量则存在于全局作用域内。脚本中所有的函数都可以访问在其主体内创建的变量。例如,在下面的代码中,变量message创建于脚本的第一行,它是一个全局变量,并且它可以被函数访问。
var message='Global variable';
function warning(){
alert(message);
}
warning();//'Global variable'
这个函数没有任何参数,并且没有定义一个message变量,因此,当alert(message)部分运行的时候,函数查找一个名为message的全局变量。在这个例子中,该变量存在,因此显示一个带有文本“Global variable”的警告框。
关于局部变量和全局变量,有一个潜在的陷阱,如果一个变量是参数,或者如果一个变量通过var关键字创建于函数的内部,它只存在于函数的作用域中。图3-9说明了这种情况。代码的上半部分展示了一个名为message的全局变量和一个名为message的函数局部变量,二者可以并列存在。关键在于,函数中的第一行代码var message='Inside the function';。通过使用var,我们创建了一个局部变量。
把这个和图3-9下半部分的代码相比较。在下半部分代码中,函数没有使用var关键字。相反,代码行message='Inside the function';没有创建一个新的局部变量;它直接把一个新值存储到全局变量message中。结果呢?这个函数干扰了全局变量,替换掉了其初始值。
图 3-9 在函数中给变量赋值的时候,有一个微妙而至关重要的区别。如果想要变量只能在函数内访问,确保在函数中使用var关键字来创建变量(如图上半部分所示)。如果没有使用var,只是把一个新值存储到全局变量中(如图下半部分所示)
变量作用域的概念确实很容易令人混淆,因此,现在提前讨论这个问题对我们没有太多意义。但是,请记住,如果在脚本中创建的变量似乎没有存储我们期望的值,可能是遇到了作用域问题。如果遇到这种情况,可以返回来阅读这一节。