前几天在项目开发过程中发现两个if语句当中定义相同的变量,居然会相互影响。代码大概如下所示:
if (1 == 1){
var obj = {name: "hello"};
$("body").click(function () {
alert(obj.name)
})
}
if (2 == 2){
var obj = {name: "Hi"}
}
点击事件触发后,发现输出的是Hi。我当时就考虑到应该和JS变量的作用域有关,所以就去学习了一下,并写下这篇文章作为记录。
在JS中定义的变量并不是以代码块为作用域,而是以函数作为作用域。比如在if、for这样的代码块当中定义变量,外边是可见的。如果在一个函数中定义变量,则在函数之外不可见。
if (1 == 1){
var a = 123;
}
function fa(){
var b = 456;
}
console.log(a) // 123
console.log(b) // 报错, b is not defiend
在JS中全局变量是指定义在函数之外的变量,局部变量则是定义在函数内的变量。函数内可以访问全局变量;反之,函数外不能访问局部变量。需要注意的是,如果定义的变量没有用var修饰,即使该变量定义在函数内,该函数也被看作是全局变量。不同的是,该函数被运行后,变量定义才生效,否则无法直接访问。我们不提倡这种写法,要求所有变量全部使用var来修饰。
function afunc() {
a = "123";
}
console.log(a); // a is not defined
function afunc() {
a = "123";
}
afunc();
console.log(a); // 123
我们在写代码的过程中应该尽量减少全局变量的数量,避免变量污染。我们可以考虑使用单一var来定义变量,即在代码第一行和函数第一行,使用一个var来定义变量。这样我们可以很方便的找到该变量,并且防止全局变量的污染。
var a = "123"
function afunc() {
alert(a)
var a = "456";
}
afunc();
如上代码,我们可能想当然的认为会输出123,可事实并非如此。输出的结果为undefined,这是为什么呢?
因为函数域是优先于全局域的,所以函数中定义的变量a会覆盖掉全局变量a。尽管alert最先执行,但是a变量已经存在,却没有被赋值。这种特殊现象被称为提升(Hoisting)。上述代码等价于:
var a = "123";
function afunc() {
var a;
alert(a)
var a = "456";
}
afunc();
至此,关于JS中变量的作用域介绍完毕!
参考文章:
js中变量的作用域