# 关键字var

前言

var声明的变量会被提升

# 1.块级作用域

作用域就是一个变量作用的范围。也就是你声明一个变量以后,这个变量可以在哪些范围下使用,var 声明的变量 只有全局作用域函数作用域

var 没有块级作用域(封闭作用域),定义后在当前的闭包中都可以访问,如果变量名重复,就会覆盖前面定义的变量,并且也有可能被其他人修改

语句后面的代码块{}var声明的变量的作用域就不是函数作用域

  • 1.同步执行
if (true) {
  var a = "a"
}
console.log(a) // a为全局作用域下的变量
1
2
3
4
  • 2.异步执行

var 覆盖之前定义的变量,同步代码执行完毕 i为 3,再执行异步代码

for (var i = 0; i < 3; i++) {
  setTimeout(() => {
    alert(i) // 三次弹窗,都是 3
  }, 0)
}
1
2
3
4
5

# 2.全局作用域

var声明变量是在函数最外部,那么此变量作用域就是全局作用域下的变量,全局都能使用这个变量

var 不支持封闭作用域,如果不是在函数里声明的变量会声明到全局作用域(window)上,在代码块中的变量外部也可以访问,而且还是放到全局作用域上面

for (var i = 0; i < 3; i++) {
  console.log(i)
}
console.log(i)
console.log(window.i)
// 0
// 1
// 2
// 3
// 3
1
2
3
4
5
6
7
8
9
10

解决方式一:使用自执行函数将其声明在函数作用域内

;(function () {
  for (var i = 0; i < 3; i++) {
    console.log(i)
  }
})()
console.log(i)
console.log(window.i)
// 0
// 1
// 2
// Uncaught ReferenceError: i is not defined
// at <anonymous>:6:13
1
2
3
4
5
6
7
8
9
10
11
12

问题二: 异步的问题

由于代码块中的代码是异步的,会被放到异步队列中执行,当代码把任务队列中的同步代码执行完毕后 i 赋值为 3,然后执行异步队列中的代码,拿到的 i 是 3

for (var i = 0; i < 3; i++) {
  setTimeout(function () {
    console.log(i)
  }, 1000)
}
// 3
// 3
// 3
1
2
3
4
5
6
7
8

解决方式

解决异步的问题

for (var i = 0; i < 3; i++) {
  ;(function (i) {
    setTimeout(function () {
      console.log(i)
    }, 1000)
  })(i)
}
// 0
// 1
// 2
1
2
3
4
5
6
7
8
9
10

# 2.1 全局变量

  • 在 if 或者 for 循环中声明的变量会变成全局变量
for (var i = 0; i <= 5; i++) {
  console.log("hello")
}
console.log(i) //5
1
2
3
4

# 2.2 变量覆盖

var a = 1
function fn() {
  console.log(a)
  if (false) {
    var a = 2
  }
}
fn() //undefined
1
2
3
4
5
6
7
8

# 3.函数作用域

var声明的变量是在函数代码块{}中声明的,那么此变量的作用域就是函数作用域下的变量,只能被此函数和函数内部的函数使用