let/var/const和无关键字声明变量有有何不同?

没有关键字

在变量赋值之前没有关键字存在,要么赋值给一个不存在的全局变量,要么重新分配给已声明的变量.在非严格模式下,如果变量没有声明,它将赋值为全局对象(浏览器中的window)的一个属性.在严格模式下,它将抛出一个错误阻止不需要的全局变量被创建.

var

直到ES2015var仍是默认的声明语句.它创建了一个函数作用域,可以重新分配和重新声明.然而,由于缺少块作用域,如果变量在一个包含异步回调的循环中再次使用的话.他可能会造成问题,因为变量将继续存在于块作用域之外.

下面,等到setTimeout回调执行时,循环已经完成啦.而且变量i的值是10,因此,所有这10个回调在这个函数作用域下引用了同一个可用的变量


for (var i = 0; i < 10; i++) {
  setTimeout(() => {
    // 打印 `10` 10 次
    console.log(i)
  })
}

/* 使用 `var` 的解决方案 */
for (var i = 0; i < 10; i++) {
  // 作为参数传递进去
  setTimeout(console.log, 0, i)
}

for (var i = 0; i < 10; i++) {
  // 创建一个函数作用域
  ;(i => {
    setTimeout(() => {
      console.log(i)
    })
  })(i)
}

let

let 在ES2015中引入,而且是新的变量声明推荐的方法,它之后将被重新分配.试图重新声明一个变量将会抛出错误.它是块级作用域,因此在循环中可以在迭代中保持它的作用域.


for (let i = 0; i < 10; i++) {
  setTimeout(() => {
    // 打印 0, 1, 2, 3, ...
    console.log(i)
  })
}

const

const 在ES2015中引入,而且是新的变量声明推荐的方法,它之后不能被重新分配,即使对象是可变的(只要对象的引用不变就行).它是块级作用域而且不能被重新分配


const myObject = {}
myObject.prop = "hello!" // 没有错误
myObject = "hello" // 抛出错误

小贴士

  • 所有的声明都会被提升到它们的作用域顶部.
  • 然而,letconst有一个叫暂时性死区的概念. 虽然声明被提升啦,但有一段时间在进入作用域和被声明之间它们是不能访问的.
  • 给你一个使用 var 的常见问题,和 let 如何解决它,以及保留 var 的解决方案
  • var应该尽可能的避免使用,推荐const作为所有变量的默认声明,除非它们之后会被重新分配,则使用let