Skip to content

变量声明

js 中可以使用 varletconst 声明变量,三者的区别见下

变量提升

  • var: 使用 var 声明的变量会发生变量提升,也就是把所有变量声明都拉到函数作用域的顶部,变量可以在声明之前使用,但其值为 undefined
    js
    console.log(a) //undefined
    var a = 100
    function fn() {
      console.log(b) //undefined
      var b = 100
    }
    fn()
  • let和const: 使用 letconst 声明的变量不会在作用域中被提升,在变量声明之前访问会存在暂时性死区
    js
    //报错:Uncaught ReferenceError: Cannot access 'a' before initialization
    console.log(a) ❌
    let a = 100

作用域

  • var: 使用 var 声明的变量具有函数作用域,这意味着变量在声明他的整个函数内部都是可访问的

    js
    function fn() {
      if (true) {
        var a = 100
      }
      //输出100,因为 a 在整个函数作用域内都可访问
      console.log(a)
    }
    fn()
  • let和const: 使用 letconst 声明的变量具有块级作用域,块级作用域用 花括号 {} 定义。变量只能在声明他的块内可访问

    js
    function fn() {
      if (true) {
        let a = 100
        const b=100
      }
      //报错:Uncaught ReferenceError: a is not defined
      // a和b只能在if块内可访问
      console.log(a) ❌
    }
    fn()

重复声明

  • var: 使用 var 声明的变量可以在同一个作用域中重复声明,后面声明的变量会覆盖前面声明的
    js
    var a=10
    var a=20
    console.log(a) //20
  • let和const: 在同一个作用域内,不需要重复声明同一个变量
    js
    let a=10
    //报错:Uncaught SyntaxError: Identifier 'a' has already been declared
    let a=20

重新赋值

  • var和let: varlet 声明的变量可以重新赋值
    js
    var a=10
    a=20
    let b=10
    b=20
  • const: const 声明的变量一旦被赋值就不能重新赋值了,但如果声明的是一个对象或者数组,可以修改其属性和元素
    js
    const a=10
    a=20//报错
    const obj={key:20}
    obj.key=20
    console.log(obj.key) //20

全局声明

使用 var全局作用域 中声明的变量会成为window对象的属性,letconst 则不会

js
var a=10
console.log(window.a) //10
let b=10
console.log(window.b) //undefined

for 循环中使用

下面这段代码会在短暂延迟后,连续输出 5 个 5。原因如下:

  1. var的特性: 因为var声明的变量具有函数作用域,在下面的代码中,for 循环中的 i 变量会被提升到函数作用域的顶部,在每次循环时,并不会创建新的变量i ,所有的 setTimeout 回调函数实际上共享的是同一个 i 变量。
  2. js的事件循环机制: setTimeout是一个异步函数,他会将传入的回调函数放在任务队列中,等待当前调用栈中的所有同步代码执行完成后才会执行,所以在这些回调函数执行之前,for 循环已经结束了,i 的值已经变成了5
js
for (var i = 0; i < 5; i++) {
  setTimeout(() => { console.log(i) }, 0)
}

如果使用let 来声明变量 i,则没有这个问题,因为let 具有块级作用域,每次循环都会创建一个新的变量 i,每个 setTimeout 引用的都是不同的变量实例

js
for (let i = 0; i < 5; i++) {
  setTimeout(() => { console.log(i) }, 0)
}
//依次输出 1、2、3、4、5

其他注意事项

js
for (var i = 0; i < 5; i++) {} 
//输出5
console.log(i);

for (let i = 0; i < 2; i++) {}
//输出5
// 注意这个i是第一个for循序中使用var声明的i
console.log(i);

for (let j = 0; j < 5; j++) {} 
//报错:j is not defined
console.log(j); ❌

区别总结

特性varletconst
变量提升存在,提升至作用域顶部并初始化为undefined✅不存在❌不存在❌
重复声明允许✅不允许❌不允许❌
重新赋值允许✅允许✅不允许,指向的引用不可变,但引用内部的数据可变❌
是否需要初始化不需要❌不需要❌需要✅