logo
Published on

什么是let和var的区别?

Authors
  • Name
    Twitter

在JavaScript中,letvar是两种常用的变量声明关键字。在实际开发中,我们经常会遇到这样的问题:“两者到底有什么区别?在什么情况下应该使用let而不是var?”这篇文章将详细解释letvar的区别。

作用域规则

var声明的变量是函数作用域(function scope)的,而let声明的变量是块作用域(block scope)的。下面的例子可以很好地展示这一点:

function run() {
  var foo = 'Foo'
  let bar = 'Bar'

  console.log(foo, bar) // Foo Bar

  {
    var moo = 'Mooo'
    let baz = 'Bazz'
    console.log(moo, baz) // Mooo Bazz
  }

  console.log(moo) // Mooo
  console.log(baz) // ReferenceError
}

run()

在这个例子中,moo变量即使在块外仍然可访问,而baz变量在块外访问时会抛出引用错误(ReferenceError)。

提升(Hoisting)

使用var声明的变量会被提升并初始化,这意味着在声明之前的作用域内可以访问,但其值是undefined。而使用let声明的变量也会被提升,但不会被初始化,在初始化前访问会抛出引用错误。

function checkHoisting() {
  console.log(foo) // undefined
  var foo = 'Foo'
  console.log(foo) // Foo
}

checkHoisting()
function checkHoisting() {
  console.log(foo) // ReferenceError
  let foo = 'Foo'
  console.log(foo) // Foo
}

checkHoisting()

创建全局对象属性

在顶层作用域中,var声明的变量会创建一个全局对象属性,而let声明的变量则不会:

var foo = 'Foo' // 全局作用域
let bar = 'Bar' // 全局作用域但不属于全局对象

console.log(window.foo) // Foo
console.log(window.bar) // undefined

重新声明

在严格模式下,var允许在同一作用域内重新声明变量,而let会抛出语法错误(SyntaxError)。

'use strict'
var foo = 'foo1'
var foo = 'foo2' // 没问题,'foo1' 被替换为 'foo2'

let bar = 'bar1'
let bar = 'bar2' // SyntaxError: Identifier 'bar' has already been declared

避免闭包问题

使用let可以避免闭包问题,它会绑定新的值,而不是保持旧的引用。看看下面的例子:

for(var i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>点击每个数字将记录到控制台:</p>
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

在这里,每个点击处理程序将引用相同的i对象,因此每次点击时显示的都是6。

使用let来避免这种问题:

for(let i=1; i<6; i++) {
  $("#div" + i).click(function () { console.log(i); });
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>点击每个数字将记录到控制台:</p>
<div id="div1">1</div>
<div id="div2">2</div>
<div id="div3">3</div>
<div id="div4">4</div>
<div id="div5">5</div>

结论

varlet之间的主要区别在于其作用域和提升行为。let在块级作用域内有效,不允许在同一作用域内重新声明,并且避免了闭包问题。在大多数情况下,建议使用let代替var,从而减少潜在的错误和提升代码的可维护性。