"let" 和 "var" 和有什么不一样?

新手上路,请多包涵

ECMAScript 6 引入 let 语句

我听说它被描述为一个局部变量,但我仍然不太确定它与 var 关键字的行为有何不同。

有什么区别?什么时候应该用 let 代替 var

原文由 TM. 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 656
2 个回答

范围规则

主要区别在于范围规则。由 var 关键字声明的变量的作用域是直接函数体(因此是函数作用域),而 let 变量的作用域是由 { } 表示的直接 封闭 块(因此是块作用域)。

 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();

let 关键字引入语言的原因是函数范围令人困惑,并且是 JavaScript 中错误的主要来源之一。

另一个 Stack Overflow 问题 看一下这个例子:

 var funcs = [];
 // let's create 3 functions
 for (var i = 0; i < 3; i++) {
 // and store them in funcs
 funcs[i] = function() {
 // each should log its value.
 console.log("My value: " + i);
 };
 }
 for (var j = 0; j < 3; j++) {
 // and now let's run each one to see
 funcs[j]();
 }

My value: 3 每次 funcs[j](); 被调用是因为匿名函数绑定到同一个变量。

人们必须创建立即调用的函数来从循环中捕获正确的值,但这也很麻烦。

吊装

虽然使用 var 关键字声明的变量被 提升(在代码运行之前使用 undefined 初始化),这意味着它们甚至在声明之前就可以在其封闭范围内访问:

 function run() {
 console.log(foo); // undefined
 var foo = "Foo";
 console.log(foo); // Foo
 }

 run();

let 变量在它们的定义被评估之前不会被初始化。在初始化之前访问它们会导致 ReferenceError 。从块的开始到处理初始化,该变量被称为处于“临时死区”。

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

 checkHoisting();

创建全局对象属性

在顶层, letvar 不同,不会在全局对象上创建属性:

 var foo = "Foo"; // globally scoped
 let bar = "Bar"; // not allowed to be globally scoped

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

重新声明

在严格模式下, var 将允许您在同一范围内重新声明相同的变量,而 let 会引发 SyntaxError。

 'use strict';
 var foo = "foo1";
 var foo = "foo2"; // No problem, 'foo1' is replaced with 'foo2'.

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

原文由 ThinkingStiff 发布,翻译遵循 CC BY-SA 4.0 许可协议

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>Clicking on each number will log to console:</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>

上面的代码演示了一个经典的 JavaScript 闭包问题。对 i 变量的引用存储在单击处理程序闭包中,而不是 i 的实际值。

每个单击处理程序都将引用同一个对象,因为只有一个计数器对象包含 6 个,因此每次单击都会得到 6 个。

一般的解决方法是将其包装在匿名函数中并将 i 作为参数传递。现在也可以通过使用 let 代替 var 来避免此类问题,如下面的代码所示。

(在 Chrome 和 Firefox 50 中测试)

 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>Clicking on each number will log to console:</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>

原文由 Gurpreet Singh 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题