JavaScript的两个特性会出人意料地创建全局变量:
- 变量即使未声明也可直接使用
- 未经声明的变量,默认为全局对象所有(暗示全局变量 implied globals)
这样一来,之后出现的全局变量,就会污染已出现的同名全局变量,导致不可预料的结果。
未经声明的变量,默认为全局对象所有:
var result = 'this is result in global';
console.log(this.result); //this is result in global
function sum(x, y) {
result = x + y;
return result;
}
console.log('sum = ' + sum(1, 3)); //4
console.log(this.result); //4 ** 此处改变了全局变量resule的值 **
使用 var 声明变量:
var result = 'this is result in global';
console.log(this.result); //this is result in global
function sum(x, y) {
var result = x + y;
return result;
}
console.log('sum = ' + sum(1, 3)); //4
console.log(this.result); //this is result in global ** 此处没有改变全局变量resule的值 **
创建隐式全局变量的反模式是带有 var/let 声明的链式赋值。在链式赋值中,只有距离声明变量 var/let 最近的变量是局部变量,其余均为全局变量,例如:
var b = 3;
function add2(x){
var a = b = 2; // ** a为局部变量,b为全局变量 **
return x + a;
}
console.log(this.b); //2 ** 此处改变了全局变量b的值 **
var b = 3;
function add2(x){
let a = b = 2; // ** a为局部变量,b为全局变量 **
return x + a;
}
console.log(this.b); //2 ** 此处改变了全局变量b的值 **
显然链式声明并没有得到预期的结果,这是因为从右至左的操作符优先级。首先,优先级比较高的是表达式b=0,此时b未经声明。表达式的返回值是0,它被赋给var声明的局部变量a,如以下代码所示:
var a = (b = 0);
如果对链式赋值的所有变量都进行了声明,就不会创建出不期望的全局变量。
var b = 3;
function add2(x){
// ** a 、b 均为局部变量**
var a, b;
a = b = 2;
return x + a;
}
console.log(this.b); //3 ** 此处没有改变全局变量b的值 **
var b = 3;
function add2(x){
// ** a 、b 均为局部变量**
let a, b;
a = b = 2;
return x + a;
}
console.log(this.b); //3 ** 此处没有改变全局变量b的值 **
所以,尽可能少地使用全局变量,是保证程序执行可预见性的必要手段。
参考资料:《JavaScript 模式》 Stoyan Stefanov 著 陈新 译
网友评论