JavaScript中的许多问题都来自于变量作用域:要么认为局部变量是全局的,要么用函数中的局部变量覆盖了全局变量。为了避免这些问题,最佳方案是根本没有任何全局变量。但是,如果你有一堆,那么你应该知道这些陷阱。
不用var关键字声明的变量是全局的。记住使用var关键字声明变量,防止变量具有全局作用域。在下面例子中,在函数中声明的变量具有全局变量,因为没有使用var关键字声明:
anonymousFuntion1 = function(){
globalvar = 'global scope'; //全局声明,因为“var”遗漏了
return localvar;
}();
alert(globalvar); //弹出“global scope”,因为函数中的变量是全局声明
anonymousFuntion2 = function(){
var localvar = 'local scope'; //使用“var”局部声明
return localvar;
}();
alert(localvar); //错误 “localvar未定义”。没有全局定义localvar
作为参数引进到函数的变量名是局部的。如果参数名也是一个全局变量的名字,像参数变量一样有局部作用域,这没有冲突。如果你想在函数中改变一个全局变量,这个函数有一个参数复制于这个全局变量名,记住所有全局变脸都是window对象的属性。
var myscope = "global";
function showScope(myscope){
return myscope; //局部作用域,即使有一个相同名字的全局变量
}
alert(showScope('local'));
function globalScope(myscope){
myscope = window.myscope; //全局作用域
return myscope;
}
alert(globalScope(’local’));
你甚至可以在循环中声明变量:
for(var i = 0; i < myarray.length; i++){}
覆盖函数/重载函数
当你不止一次的声明一个函数时,这个函数的最后一次声明将覆盖掉该函数的所有前面版本且不会抛出任何错误或警告。这不同于其他的编程语言,像Java,你能用相同的名字有多重函数,只要它们有不同的参数:调用函数重载。在JavaScript中没有重载。这使得不能在代码中使用JavaScript核心部分的名字极其重要。也要当心包含的多个JavaScript文件,像一个包含的脚本文件可能覆盖另一个脚本文件中的函数。请使用匿名函数和名字空间。
(function(){
// creation of my namespace 创建我的名字空间
if(!window.MYNAMESPACE) {
window['MYNAMESPACE'] = {};
}
//如果名字空间不存在,就创建它
//这个函数仅能在匿名函数中访问
function myFunction(var1, var2){
//内部的函数代码在这儿
}
// 把内部函数连接到名字空间上,使它通过使用名字空间能访问匿名函数的外面
window['MYNAMESPACE']['myFunction'] = myFunction;
})(); // 圆括号 = 立即执行
// 包含所有代码的圆括号使函数匿名
这个例子正式为了实现解决上一个陷阱“变量作用域”的最佳方案。匿名函数详细内容请看《Javascript的匿名函数》。YUI整个库只有 YAHOO和YAHOO_config两个全局变量,它正是大量应用匿名函数和命名空间的方法来实现,具体请看《Javascript的一种模块模式》。
字符串替换
一个常见错误是假设字符串替换方法的行为会对所有可能匹配都产生影响。实际上,JavaScript字符串替换只改变了第一次发生的地方。为了替换所有发生的地方,你需要设置全局标识。同时需要记住String.replace()的第一个参数是一个正则表达式。
var myString = "this is my string";
myString = myString.replace("","%20"); // "this%20is my string"
myString = myString.replace(/ /,"%20"); // "this%20is my string"
myString = myString.replace(/ /g,"%20"); // "this%20is%20my%20string"
parseInt
在JavaScript得到整数的最常见错误是假设parseInt返回的整数是基于10进制的。别忘记第二个参数基数,它能是从2到36之间的任何值。为了确保你不会弄错,请一直包含第二个参数。
parseInt('09/10/08'); //0
parseInt(’09/10/08′,10); //9, 它最可能是你想从一个日期中得到的值
如果parseInt没有提供第二个参数,则前缀为 ‘0x’ 的字符串被当作十六进制,前缀为 ‘0′ 的字符串被当作八进制。所有其它字符串都被当作是十进制的。如果 numString 的前缀不能解释为整数,则返回 NaN(而不是数字)。
‘this’
另一个常见的错误是忘记使用“this”。在JavaScript对象中定义的函数访问这个对象的属性,但没有使用引用标识符“this”。例如,下面是错误的:
function myFunction() {
var myObject = {
objProperty: "some text",
objMethod: function() {
alert(objProperty);
}
};
myObject.objMethod();
}
function myFunction() {
var myObject = {
objProperty: "some text",
objMethod: function() {
alert(this.objProperty);
}
};
myObject.objMethod();
}
有一篇 A List Apart文章 用通俗易懂的英文表达了this绑定的问题。
对this使用最大的陷阱是this在使用过程中其引用会发生改变: