- Published on
什么是let和var的区别?
- Authors
- Name
在JavaScript中,let
和var
是两种常用的变量声明关键字。在实际开发中,我们经常会遇到这样的问题:“两者到底有什么区别?在什么情况下应该使用let
而不是var
?”这篇文章将详细解释let
和var
的区别。
作用域规则
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>
结论
var
与let
之间的主要区别在于其作用域和提升行为。let
在块级作用域内有效,不允许在同一作用域内重新声明,并且避免了闭包问题。在大多数情况下,建议使用let
代替var
,从而减少潜在的错误和提升代码的可维护性。