• var定义的变量，没有块的概念，可以跨块访问, 不能跨函数访问。 let定义的变量，只能在块作用域里访问，不能跨块访问，也不能跨函数访问。 const用来定义常量，使用时必须初始化(即必须赋值)，只能在块作用域里访问...
var定义的变量，没有块的概念，可以跨块访问, 不能跨函数访问。
let定义的变量，只能在块作用域里访问，不能跨块访问，也不能跨函数访问。
const用来定义常量，使用时必须初始化(即必须赋值)，只能在块作用域里访问，而且不能修改。


展开全文
• var和let和const Var (Var) Using var declares either a locally(within function) scoped variable or a globally scoped variable. 使用var声明局部(函数内)范围的变量或全局范围的变量。 范围 (Scope) When ...
var和let和const Var (Var)
Using var declares either a locally(within function) scoped variable or a globally scoped variable. 使用var声明局部(函数内)范围的变量或全局范围的变量。
范围 (Scope)
When var is used outside a function, it declares a globally scoped variable. 当在函数外使用var时，它将声明一个全局范围的变量。
var a = 2; // globally scoped variablefunction foo() {    console.log(a);}foo(); // prints out 2console.log(window.a); // prints out 2This is similar to adding a property to window object directly, while there is a difference: you can’t delete the variable declared using var. 这类似于直接向窗口对象添加属性，但有一个区别：您不能删除使用var声明的变量。
var a = 2; // globally scoped variablewindow.b = 3; // new property of window object, also globally scopeddelete a; // returns falsedelete b; // returns trueWhen var is used inside a function definition, it creates a local variable which is only available within the function: 当在函数定义中使用var时，它将创建仅在函数中可用的局部变量：
function bar() {    var a = 2; // only available inside this function    console.log(a);}bar(); // prints out 2console.log(a); // Uncaught ReferenceError: a is not definedconsole.log(window.a); // prints out undefinedIf you happen to forget to add var in a function when declare a variable, it becomes a globally scoped variable. 如果您在声明变量时忘了在函数中添加var，它将成为全局范围的变量。
function foo() {    a = 2; // note there is no var in front of the variable name    console.log(a);}foo(); // prints out 2console.log(a); // prints out 2console.log(window.a); // prints out 2It may not be what you intended to do, for example: 它可能不是您打算要做的，例如：
var a = 2;function foo() {    a = 3; // the value of the global variable a is overwritten here    console.log(a);}console.log(a); // prints out 2foo(); // prints out 3console.log(a); // prints out 3, the old value got overwritten 吊装 (Hoisting)
The variables declared with var are hoisted, which means you can use the variables even before it reaches the line in the code it declares the variable. 用var声明的变量被吊起，这意味着您甚至可以在变量到达声明变量的代码中的行之前使用这些变量。
console.log(a); // prints out undefined. This doesn't mean the variable a is not defined. It means the value of a is undefineda = 2;console.log(a); // prints out 2 as we just assigned a value to itvar a;Note that if you try out above example in Chrome console, copy and paste above code snippet in one shot, i.e. don’t copy and execute each line one at a time; otherwise you’ll get a “Uncaught ReferenceError: a is not defined” error. 请注意，如果您在Chrome控制台中尝试上述示例，请一次性复制并粘贴以上代码段，即不要一次复制并执行每一行； 否则，您将收到“ Uncaught ReferenceError：未定义”错误。
让 (Let)
Using let declares a block scoped variable. 使用let声明块范围的变量。
范围 (Scope)
The variable declared with let is only available within the code block it is defined. 用let声明的变量仅在定义的代码块中可用。
{ // note the curly bracket here    let a = 2;    console.log(a); // prints out 2}console.log(a); // Uncaught ReferenceError: a is not definedUnlike var, the variables declared with let is not added to window object as a property even if it is globally accessible. 与var不同，使用let声明的变量即使可全局访问，也不会作为属性添加到window对象。
let a = 2;function foo() {    console.log(a);}foo(); // prints out 2console.log(a); // prints out 2console.log(window.a); // prints out undefinedUnlike var, you can not re-declare a let variable in the same scope. 与var不同，您不能在同一范围内重新声明let变量。
let a = 2; // declare for the first time, no problemlet a = 2; // Uncaught SyntaxError: redeclaration of let aA fun fact is that both Chrome (84.0.4147.105) console and Microsoft Edge (83.0.478.61) allow this redeclaration, while FireFox (78.0.2) and Safari (13.1.1) don’t. 一个有趣的事实是Chrome(84.0.4147.105)控制台和Microsoft Edge(83.0.478.61)都允许重新声明，而FireFox(78.0.2)和Safari(13.1.1)不允许。
吊装 (Hoisting)
The variables declared with let are not hoisted to the top, hence let variable is still not yet initialized with undefined if user use it before declaration. That’s why there is a temporal death zone, i.e., browsers will report an error if one use the let variable before declaration. 用let声明的变量未提升到顶部，因此，如果用户在声明之前使用let，则let变量仍未使用undefined初始化。 这就是为什么存在临时死亡区的原因，即，如果一个浏览器在声明之前使用let变量，则浏览器将报告错误。
function foo() {    console.log(a);    let a;}foo(); // Uncaught ReferenceError: Cannot access 'a' before initializationfunction bar() {    let b;    console.log(b);}bar(); // prints undefined 康斯特 (Const)
Using const declares and initializes a block scoped constant. If the constant is a primitive type (string, number, bigint, boolean, undefined, and symbol) or null, the value could not be altered after initialization. 使用const声明并初始化块作用域常量。 如果常量是原始类型(字符串，数字，bigint，布尔值，未定义和符号)或为null，则初始化后不能更改该值。
{    const a = 2;    a = 3; // Uncaught TypeError: Assignment to constant variable.}While if it points to an object, the properties can be modified/added/deleted. The only thing that cannot be modified is the memory address of the object to which the constant is pointing. 如果它指向一个对象，则可以修改/添加/删除属性。 唯一不能修改的是常量指向的对象的内存地址。
{    const a = {};    a.foo = "hello";    a.bar = "world";    console.log(a.foo); // prints out hello    console.log(a.bar); // prints out world} 范围 (Scope)
Like let, const constants are block scoped. 像let一样，const常量是块范围的。
{    const a = 2;    console.log(a); // prints out 2}console.log(a); // Uncaught ReferenceError: a is not definedIn addition, browsers don’t allow redeclaration of constant in the same block scope, even in Chrome and Microsoft Edge. 此外，即使在Chrome和Microsoft Edge中，浏览器也不允许在同一块范围内重新声明常量。
吊装 (Hoisting)
Like let, const constants are not available before declaration, i.e. browser will report an error if one use it before declaration. 像let一样，const常量在声明之前不可用，即如果在声明之前使用const常量，浏览器将报告错误。
翻译自: https://medium.com/@wenhe.qi/understanding-var-let-and-const-with-examples-81dd3ae78c2avar和let和const
展开全文
• var和let和constby Prarthana S. Sannamani 通过Prarthana S.Sannamani 用故事讲解JavaScript的var，let和const变量 (JavaScript’s var, let, and const variables explained with a story) In this article, we ...
var和let和constby Prarthana S. Sannamani 通过Prarthana S.Sannamani
用故事讲解JavaScript的var，let和const变量 (JavaScript’s var, let, and const variables explained with a story)
In this article, we will explore the history of var in JavaScript, the need for let and const, and the differences between them. 在本文中，我们将探讨JavaScript中var的历史， let和const的需求以及它们之间的区别。
This post consists of two sections: Fictional piece and Technical explanation. 这篇文章分为两部分：虚构作品和技术说明。
The fictional piece is intended to ease beginners into the concepts, but several parts are simplified and do not always present an accurate 1:1 analogy. 该虚构作品旨在使初学者更容易理解这些概念，但是简化了几个部分，并不一定总是提供准确的1：1类比。
Let’s start! 开始吧！
三个变量的故事 (A tale of three variables)
JavaScript town was a bustling town beside the sea with a commercial district filled with high rise buildings. JavaScript镇是一个繁华的小镇，在海边，有一个充满高层建筑的商业区。
Since time immemorial, the residents of JavaScript town used Vary boxes to store their valuables, especially their prized gold marbles. To do so, the residents had two options: 自远古时代起，JavaScript镇的居民就使用Vary盒子存放他们的贵重物品，尤其是珍贵的黄金大理石。 为此，居民有两种选择：
They could place the gold marbles directly in the box (pass by value) 他们可以将黄金弹珠直接放在盒子中(按值传递) If they had a large number of gold marbles so that they would not fit in the box, they could place a special piece of paper in the box, which indicated where they had stored them. For example, the piece of paper could say “second drawer in the storage cabinet” (pass by reference) 如果他们有大量的金色大理石，以致它们无法放入盒子中，则可以在盒子中放一张特殊的纸，指明它们的存放位置。 例如，一张纸上可能写着“储物柜中的第二个抽屉”(通过引用) Since the town prided itself on law and order, they set up several rules and procedures. 由于该镇以治安为荣，他们制定了一些规则和程序。
店铺规则 (Rules for shops)
To maintain the serenity of the town, shops could be built only on hills (functions create their own local scope) 为了保持小镇的宁静，商店只能在山丘上建造(功能会建立自己的本地范围) The only exception to Rule 1 was the special shop at sea level (global scope). 规则1的唯一例外是在海平面(全球范围)的特殊商店。 A shop could have inner shops to help cover the rent (nested functions). However, each inner shop was required to be on a higher hill than the landlord shop’s hill (local function scope). 商店可以有内部商店来帮助支付租金(嵌套功能)。 但是，每个内部店铺都必须位于比房东店铺的山高的地方(当地职能范围)。 A shop could have “special offer” counters, such as “If you are over 20 years old, buy a special box here.” And “For (every) child of your family, buy a kid’s box here” (other blocks such as if and loops). 一家商店可能设有“特价”柜台，例如“ If您超过20岁，请在这里购买一个特殊的盒子。” 还有“ For您家的(每个)孩子来说of在这里购买一个孩子的盒子”(其他街区，例如if和loops)。 Each shop was required to have a “declaration-initialization” counter with a guard at the entrance, who maintained a registration log book (hoisting at the top of corresponding scope). 每个商店都必须在入口处设有一个“申报初始化”柜台，并配备一个门卫，该门卫维护着登记日志(悬挂在相应范围的顶部)。 Each shop could have unlimited “assignment” counters with a shop assistant, who would place a resident’s gold marbles in the box. 每家商店可以与一名售货员建立无限的“分配”柜台，售货员将居民的黄金大理石放在盒子里。  盒子市场监管规则 (Rules for box market regulation)
The boxes could be purchased only from the sea level special shop or from a shop on the hills (variable can have global or local scope). 只能从海平面专卖店或山上的商店购买这些盒子(变量可以具有全球范围或局部范围)。 At the sea level or on any hill, residents could own ONLY a single colored Vary box (duplicate identifiers not allowed). 在海平面或任何山丘上，居民只能拥有一个彩色的Vary框(不允许使用重复的标识符)。 The Vary box could never be empty from the moment it was created. It had to contain cotton (undefined) or gold marbles at all times (effect of hoisting). 自创建之日起， Vary框就永远不能为空。 它必须始终包含棉花( undefined )或金色大理石(提升效果)。 Once a resident exited a shop (and hence, descended the hill), all boxes they purchased in it disappeared (end of variable’s scope). 一旦居民离开商店(因此从山上下来)，他们在商店里购买的所有盒子都消失了(变量作用域的末端)。  居民购买“ Vary”盒子的程序 (Procedure for residents to buy the Vary boxes)
John enters the shop and declares what color of Vary box he desires to buy at the “declaration-initialization” counter. The guard notes this in his registration book. 约翰进入商店，并在“申报初始化”柜台上宣布想要购买哪种颜色的Vary盒子。 保安员在他的登记簿中记录了这一点。 The guard conjures the colored Vary box, fills it with cotton and hands it to John. 守卫让人想起彩色的Vary盒子，里面装满棉花，然后交给John。 John gets a ticket for his turn and when it arrives, he heads to the “assignment” counter. Until then, he can hold his box but cannot place his gold marbles in it. 约翰得到轮到他的车票，到时，他去了“分配”柜台。 在此之前，他可以拿着盒子，但不能在盒子里放金弹。 At the counter, John hands over his box and gold marbles to the shop assistant, who removes the cotton, places the gold marbles inside and hands it back to him. 在柜台上，约翰将他的盒子和金大理石交给了店员，店员将棉花取出，将金大理石放在里面，然后交给他。 Naturally, these rules brought along peculiar problems. 这些规则自然会带来特殊的问题。
With long waiting times for the “assignment” counter, John would forget that he had not placed his gold marbles in his box yet. He would open it to brag to his friends and find only cotton. Bummer! 约翰在等待“分配”柜台的时间很长时，会忘记他还没有将金色大理石放在盒子里。 他会打开它向朋友吹嘘，只发现棉花。 mm！ Often, John would forget that he had already bought a certain colored box in a shop and newly register for the same colored box again. This would instantly result in the disappearance of his existing box (and gold marbles!!), followed by the guard conjuring a new box filled with cotton. No warning! This was especially prevalent at the “special offers” counters. 通常，约翰会忘记自己已经在商店里购买了某个彩盒，然后又重新注册了该彩盒。 这将立即导致他现有的盒子(和金色弹珠！)消失，随后警卫人员将一个新盒子装满棉花。 没有警告！ 这在“特别优惠”柜台上尤其普遍。 You can imagine how frustrating this situation was. With the residents of JavaScript town losing their marbles, the Town Council decided to take action. 您可以想象这种情况多么令人沮丧。 随着JavaScript镇的居民失去大理石，镇议会决定采取行动。
In a grand Town Meeting in 2015, they proudly introduced two new boxes: Lety and Consty. 在2015年的一次大型城镇会议上，他们自豪地推出了两个新包装盒： Lety和Consty 。
They also introduced the other major change: the removal of “special offer” counters from Lety and Consty shops. Instead, these counters were upgraded to inner shops, which were built on a hill inside the shop. 他们还介绍了另一个重大变化：从Lety和Consty商店中删除“特价”柜台。 相反，这些柜台被升级为内部商店，内部商店建在商店内部的小山上。
购买“ Lety”和“ Consty”盒子的规则 (Rules for purchasing Lety and Consty boxes)
John enters the shop and declares what type and color of box he desires to buy at the “declaration” counter. The guard notes this in his registration book. This information hazily appears on the huge wall clock, which can be seen, but not used, and is referred to as the “temporal dead zone”. 约翰进入商店，并在“声明”柜台上声明了他想要购买的盒子的类型和颜色。 保安员在他的登记簿中记录了这一点。 该信息模糊地出现在巨大的挂钟上，可以看到但没有使用，被称为“临时死区”。 John gets a ticket for his turn. Since the box is not created at declaration, it is not available for use. 约翰轮到他了。 由于该框不是在声明时创建的，因此无法使用。 This is where Lety and Consty purchase rules diverge. 这是Lety和Consty购买规则不同的地方。
Lety规则： (Lety rules:)
Once John’s turn arrives, he heads to the “initialization” counter. 约翰轮到了，他前往“初始化”柜台。 At the counter, John has the choice to buy an empty Lety box, or buy a Lety box and have his gold marbles placed inside it immediately. 在柜台上，John可以选择购买一个空的Lety盒子，或购买一个Lety盒子并立即将其金色大理石放在里面。 Depending on his choice, the shop assistant conjures the Lety box, and fills it with cotton or hands it over to the “assignment” counter, where John’s gold marbles are placed inside it. 根据他的选择，店员会变出Lety盒子，并用棉花填充它或将其移交给“分配”柜台，John的金色大理石放在里面。  Consty规则 (Consty rules)
Consty boxes are extremely special. Lined with a layer of gold inside and sealed with a lock, these boxes are so dear to the shop assistants that they refuse to sell them without knowing what exactly will be placed in them. Consty盒子非常特别。 这些盒子内衬有一层黄金，并用锁密封，对售货员是如此珍爱，以至于他们拒绝出售它们而又不知道它们到底要放什么。
Once John’s turn arrives, he heads to the “initialization-assignment” counter. 轮到约翰后，他前往“初始化分配”柜台。 John is required to hand over his gold marbles to the shop assistant, who conjures the colored Consty box, places the gold marbles inside, and locks the box forever. 约翰被要求将他的金弹珠移交给售货员，店员会变出彩色的Consty盒子，将金弹珠放进去，并永远锁住盒子 。 If you remember, John could directly place his gold marbles in the box or place a special piece of paper which indicated the location of his gold marbles. 如果您还记得的话，John可以直接将他的金色大理石放在盒子里，也可以放一张特殊的纸来标明他的金色大理石的位置。
If he places his gold marbles inside the Consty box, he cannot add or remove them anymore. They are locked forever. 如果他将自己的金色大理石放在Consty框中，则无法再添加或删除它们。 他们永远被锁定。 However, if he places the special piece of paper, it is a little different. While he cannot replace the paper, he can add or remove his gold marbles at the location he has specified on the paper. 但是，如果他放特殊纸，则有些不同。 尽管他不能更换纸张，但是他可以在纸张上指定的位置添加或移除他的金弹珠。 Let’s go back to the peculiar problems that prompted the invention of Lety and Consty boxes, and decide if they are resolved. 让我们回到促使Lety和Consty盒子发明的特殊问题，并确定它们是否得到解决。
With long waiting times for the “assignment” counter, John would forget that he had not placed his gold marbles in his box yet. He would open it to brag to his friends and find only cotton. Bummer! 约翰在等待“分配”柜台的时间很长时，会忘记他还没有将金色大理石放在盒子里。 他会打开它向朋友吹嘘，只发现棉花。 mm！
Since Lety and Consty boxes are not created until John heads over to the “initialization” or ”initialization-assignment” counter, respectively, he knows he does not have the box, and thus, does not try to use it. Even if he does, loud alarms installed in the shops start ringing to alert him of the fact. 由于Lety和Consty框是在John分别转到“初始化”或“初始化分配”计数器之前才创建的，因此他知道自己没有该框，因此不会尝试使用它。 即使他这样做，商店中安装的响亮警报也会响起，以提醒他这一事实。
Often, John would forget that he had already bought a certain colored box in a shop and newly register for same colored box again. This would instantly result in the disappearance of his existing box (and gold marbles!!), followed by the guard conjuring a new box filled with cotton. No warning! This was especially prevalent at the “special offers” counters. 通常，约翰会忘记自己已经在商店里购买了某个彩盒，然后又重新注册了该彩盒。 这将立即导致他现有的盒子(和金色的大理石弹珠！)消失，接着是警卫人员召唤出一个装满棉花的新盒子。 没有警告！ 这在“特别优惠”柜台上尤其普遍。
This is handled by the removal of the “special offers” counters and the introduction of the below rule: 这可以通过删除“特价”柜台和引入以下规则来解决：
Once a resident registers for a certain colored box at the “declaration”desk in the Lety or Consty shops, he cannot re-register for the same colored box anymore in that shop! If he does, loud alarms will start blaring. 一旦居民在Lety或Consty商店的“声明”柜台注册了某个彩色框，他就无法在该商店重新注册相同的彩色框！ 如果他这样做，响亮的警报将开始刺耳。
These wonderful new boxes and rules bought peace and serenity to JavaScript Town once again, and everyone lived happily ever after. 这些奇妙的新盒子和规则再次为JavaScript Town带来了和平与安宁，从此以后每个人都过着幸福的生活。
深入技术细节 (Diving into the technical details)
Let’s go over the technical aspects of var, let and const to understand the story. 让我们回顾一下var ， let和const的技术方面，以了解故事。
If you are unfamiliar with hoisting and scope (function-level and block-level), I recommend that you read my previous article here. 如果您不熟悉提升和范围(功能级别和块级别)，建议您在此处阅读我的上一篇文章。
Here is an extract to understand the hills analogy I have used above: 这是理解我上面使用的山丘类比的摘录：
To increase our understanding of block level and function level scope, let us consider the analogy of hills. Assume that global scope is the land at sea level and local scopes are hills. If you stand on top of a hill, you can see (access) variables below your altitude. However, if you are sea level, you cannot see (access) variables at a higher altitude. 为了增加对块级别和功能级别范围的理解，让我们考虑一下希尔的类比。 假设全球范围是海平面上的土地，本地范围是山丘。 如果您站在山顶上，可以看到(进入)海拔以下的变量。 但是，如果您处于海平面，则无法在更高的高度看到(访问)变量。
In C++, every block {} results in the formation of a new hill (local scope), at an altitude one level higher than the one it is enclosed in. Nested blocks result in multi-level hills. 在C ++中，每个块{}都会形成一个新的山(局部作用域)，其高度比其所围成的山高1层。嵌套的块会形成多层山。 In JavaScript, only a function results in the formation of a new hill (local scope). Other blocks such as if blocks are present on the same altitude. 在JavaScript中，只有函数会导致形成新的小山(本地范围)。 其他街区(例如， if街区位于同一高度)。 Therefore, if a variable is declared on a certain hill (block), it can be accessed from that hill (block) and all hills (blocks) above it. 因此，如果在某个山丘(块)上声明了变量，则可以从该山丘(块)及其上方的所有山丘(块)进行访问。
变量的生命周期 (Life cycle of a variable)
Declaration Phase: Registration of a variable in its scope, which can be global/function/block scope. In this phase, no memory is allocated yet. 声明阶段 ：在变量范围内注册变量，该变量可以是全局/功能/块范围。 在此阶段，尚未分配内存。
Initialization Phase: Allocation of memory for the variable, where a binding is created, and the variable is initialized with undefined. 初始化阶段 ：为变量分配内存，在此创建绑定，并使用undefined初始化变量。
Assignment Phase: Assignment of a value to the variable. 分配阶段 ：将值分配给变量。
It is important to note that variable declaration and declaration phase are not the same! 重要的是要注意变量声明和声明阶段不一样！
A variable declaration is a statement such as var a. 变量声明是诸如var a类的语句。
The declaration phase is a step carried out by the JavaScript compiler. In this step, when the compiler encounters a variable declaration, it declares/registers it in its corresponding scope (if the declaration does not already exist). Later on, the code generated by the compiler is executed by the JavaScript engine. 声明阶段是JavaScript编译器执行的步骤。 在此步骤中，当编译器遇到变量声明时，它将在其相应的范围内声明/注册它(如果声明尚不存在)。 稍后，由编译器生成的代码由JavaScript引擎执行。
变种 (var)
global scope or function scope 全局范围或功能范围 value can be updated 值可以更新 can be re-declared 可以重新声明 hoisted: registered in the scope, and initialized with undefined 吊起：在范围内注册，并用undefined初始化 Below is a simple example where we initialize a variable, update its value, and re-declare it. 下面是一个简单的示例，其中我们初始化变量，更新其值并重新声明。
// Hoistedconsole.log(a); // undefinedvar a = 10;console.log(a); // 10a = 20; // value updated: OKconsole.log(a); // 20var a = 30; // re-declared: OKconsole.log(a); // 30At the top of the scope, all variables are declared in their corresponding scope and initialized with a value of undefined. Registration and initialization are coupled. Thus, variable a is available for use from the top of the scope. So when we try to access the value of a before it is declared, it does not throw an error. Rather, undefined is printed. This is known as variable hoisting. 在作用域的顶部，所有变量都在其对应的作用域中声明，并使用undefined值初始化。 注册和初始化是耦合的。 因此，变量a可从范围的顶部使用。 因此，当我们尝试在声明a之前访问其值时，它不会引发错误。 而是打印undefined 。 这称为可变提升。
Below is an example that shows the function scope of var. 下面的示例显示var的功能范围。
function outerFunc() {  var a = 10;  if (a > 5) {    var a = 20;    console.log(a); // 20  }  console.log(a); // 20}Variable a is initially declared in the scope of outerFunc. Since the if block does not create a new scope, when we re-declare variable a, the earlier variable a gets wiped away and a new variable a gets created with a value of 20. 变量a最初在outerFunc的范围内声明。 由于if块不会创建新的作用域，因此当我们重新声明变量a ，较早的变量a会消失，而创建的新变量a的值为20 。
Accidental re-declaration of var variables is a common mistake developers make due to silent re-declaration and confusion in understanding function scope. 意外重新声明var变量是开发人员由于无声的重新声明和对函数范围的理解上的混乱而经常犯的错误。
让 (let)
block scoped 块作用域 value can be updated 值可以更新 cannot be re-declared 不能重新声明 hoisted but not initialized 悬挂但未初始化 Below is a simple example where we initialize a variable, update its value, and try to re-declare it. 下面是一个简单的示例，其中我们初始化变量，更新其值并尝试重新声明它。
console.log(a); //   ReferenceError: a is not definedlet a = 10;console.log(a); // 10a = 20;console.log(a); // 20let a = 30; // SyntaxError: Identifier 'a' has already been declaredUpdating a let variable is allowed. However, if you try to re-declare it, you encounter a SyntaxError. This protects developers from silent and accidental re-declaration of variables. 允许更新let变量。 但是，如果尝试重新声明它，则会遇到SyntaxError 。 这样可以保护开发人员免于无声且无意间重新声明变量。
Are let variables hoisted? 是否let变量挂起？
This is a tricky question. The internet is divided on this: there are arguments for both sides. Some developers believe that let (and const) variables are not hoisted, because they cannot be accessed before their declaration statement is reached, unlike var. However, this answer really depends on your definition of hoisting. If hoisting is the coupling of the declaration and initialization phases of a variable at the top of its corresponding scope, then let and const variables are not hoisted. 这是一个棘手的问题。 互联网对此有分歧：双方都有争论。 一些开发人员认为， let (和const )变量不会被悬挂，因为与var不同，无法在到达声明语句之前访问它们。 但是，这个答案实际上取决于您对起重的定义。 如果提升是变量的声明和初始化阶段在其相应范围的顶部耦合，则let和const变量不会被提升。
However, after reading several opinions and not being any closer to the truth, I decided to go with MDN’s definition of hoisting. 但是，在阅读了几条意见之后，我并没有更接近事实，我决定采用MDN的起重定义。
let bindings are created at the top of the (block) scope containing the declaration, commonly referred to as "hoisting". (MDN) let绑定在包含声明的(块)作用域的顶部创建，通常称为“提升”。 (MDN) According to this definition, the answer to our question is yes. let variables are hoisted, but they are not initialized with undefined. Thus, they exist in a time period called the “Temporal Dead Zone” from the start of the block until their definition is evaluated. Trying to access them in TDZ throws a ReferenceError, as seen in the example. 根据这个定义，我们问题的答案是肯定的。 悬挂let变量，但不使用undefined初始化它们。 因此，它们从块的开始一直存在到称为“临时死区”的时间段，直到评估其定义为止。 如示例所示，尝试在TDZ中访问它们会引发ReferenceError 。
Below is an example that shows block scope of let. 下面是显示let块范围的示例。
function outerFunc() {  let a = 10;  if (a > 5) {    let a = 20;    console.log(a); // 20  }  console.log(a); // 10}The first declaration of variable a is in the scope of outerFunc. The if block creates a new scope, and when we make the second declaration of variable a, it gets registered in the new scope. This is independent from the outerFunc scope. Hence, a separate variable a is created, and we can observe that changes to the inner variable a do not affect the outer variable a. 变量a的第一个声明在outerFunc的范围内。 if块创建一个新的作用域，当我们对变量a进行第二次声明时，它将在新作用域中注册。 这与outerFunc范围无关。 因此，创建了一个单独的变量a ，我们可以观察到对内部变量a更改不会影响外部变量a 。
This allows developers to easily create temporary variables inside condition and looping blocks, without having to search if the variable already exists in the function. 这使开发人员可以轻松地在条件和循环块内创建临时变量，而不必搜索该函数中是否已存在该变量。
const (const)
block scoped 块作用域 binding is immutable (but value may or may not be changed) 绑定是不可变的(但值可能会更改，也可能不会更改) cannot be re-declared 不能重新声明 hoisted but not initialized 悬挂但未初始化 Below is a simple example where we initialize a variable, try to update its value, and try to re-declare it. 下面是一个简单的示例，其中我们初始化变量，尝试更新其值，然后尝试重新声明它。
console.log(a); //  ReferenceError: a is not definedconst a = 10;console.log(a); // 10a = 20; // TypeError: Assignment to constant variable.const a = 30; // SyntaxError: Identifier 'a' has already been declaredconst b; // SyntaxError: Missing initializer in const declarationSimilar to let variables, const variables are hoisted, but not initialized with undefined. Trying to access them in the Temporal Dead Zone throws a ReferenceError. 与let变量类似， const变量是悬挂的，但不使用undefined初始化。 尝试在临时死区中访问它们会引发ReferenceError 。
If we try to initialize a const variable without an assignment, as in the example above for const b; , we encounter a SyntaxError: Missing initializer in const declaration. Similarly, we cannot re-declare const variables. It leads to a SyntaxError. 如果我们尝试在没有赋值的情况下初始化const变量，如上面const b;的示例所示const b; ，我们SyntaxError: Missing initializer in const declaration遇到SyntaxError: Missing initializer in const declaration 。 同样，我们不能重新声明const变量。 它导致一个SyntaxError 。
Let’s temporarily hold off our discussion of updating const variables. 让我们暂时停止有关更新const变量的讨论。
Below is an example of block level scope of const variables: 以下是const变量的块级范围的示例：
function outerFunc() {  const a = 10;  if (a > 5) {    const a = 20;    console.log(a); // 20  }  console.log(a); // 10}The above behavior is similar to let variables, where a new scope is created for the if block, and hence, changes to the inner variable a do not affect the outer variable a. 上面的行为类似于let变量，其中为if块创建了一个新作用域，因此，对内部变量a更改不会影响外部变量a 。
Let’s return to the discussion of updating const variables. 让我们回到更新const变量的讨论。
There is a common misunderstanding that const variables hold constant values, and cannot ever be updated. However, const works differently. 常见的误解是const变量具有常量值，并且永远无法更新。 但是， const工作方式有所不同。
After the initial assignment, the binding of const variables is immutable., and therefore, the reference to what is stored inside the const variable cannot be modified. In the simplest terms, this means you cannot have a statement with just the const variable on the left hand side, followed by an equal sign = , and a new value on the right hand side. 初始分配后， const变量的绑定是不可变的 ，因此，无法修改对const变量内部存储内容的引用 。 用最简单的术语来说，这意味着您不能拥有仅在左侧具有const变量，后跟等号=以及在右侧具有新值的语句。
However, whether the value can be updated depends on what is stored in it. Let’s consider the two cases: 但是，该值是否可以更新取决于其中存储的内容。 让我们考虑两种情况：
Primitive data type: Boolean, Null, Undefined, Number, String, Symbol 基本数据类型：布尔，空，未定义，数字，字符串，符号 Objects 对象 If a variable is assigned a primitive data type, the data type gets passed by value. Hence, if we have a statement let x = 10 , we can visualize x containing the Number 10. 如果为变量分配了原始数据类型，则该数据类型将通过value传递。 因此，如果我们有一个let x = 10的语句，我们可以可视化包含数字10 x 。
If a variable is assigned an object, the object is passed by reference. Hence, if we have a statement let x = [1,2,3], x does not contain the array [1,2,3] . Instead, it contains a reference (address) of where the array [1,2,3] is stored in memory after its creation. Hence, we can visualize x containing an address such as 5274621. 如果为变量分配了对象，则该对象将通过reference传递。 因此，如果我们有一个语句let x = [1,2,3] ，则x不包含数组[1,2,3] 。 相反，它包含数组创建后在内存中存储的数组[1,2,3]的引用(地址)。 因此，我们可以可视化包含地址(例如5274621 x 。
Let’s see examples from primitive and object data types: 让我们看一下原始和对象数据类型的示例：
// Booleanconst a = true;a = false; // TypeError: Assignment to constant variable.// Nullconst b = null;b = 10; // TypeError: Assignment to constant variable.// Undefinedconst c = undefined;c = 10; // TypeError: Assignment to constant variable.// Numberconst d = 50;d = 100; // TypeError: Assignment to constant variable.// Stringconst e = 'hello';e = 'world'; // TypeError: Assignment to constant variable.// Symbolconst f = Symbol('foo');f = 100; // TypeError: Assignment to constant variable.As we can see above, trying to update the value of any primitive data type results in a TypeError. 如上所示，尝试更新任何原始数据类型的值都会导致TypeError 。
/* Arrays are stored by reference.Hence, although the binding is immutable, the values are not. */const c = [1,2,3];c.push(10); // No errorconsole.log(c); // [1,2,3,10]c.pop(); // No errorconsole.log(c); // [1,2,3]c = [4,5,6]; // TypeError: Assignment to constant variable.As we can see above, we can push and pop items from the array since this only modifies the contents of what the const variable is pointing to, but does not try to overwrite the contents of the const variable itself. However, if we try to update the binding of the const variable by re-assigning it a completely new array c = [4,5,6], it throws a TypeError. 正如我们在上面看到的，我们可以从数组中推送和弹出项目，因为这只会修改const变量指向的内容，而不会尝试覆盖const变量本身的内容。 但是，如果尝试通过为const变量重新分配一个全新的数组c = [4,5,6]来更新const变量的绑定，则会抛出TypeError 。
/* Objects are stored by reference.Hence, although the binding is immutable, the values are not. */const d = { name: 'John Doe', age: 35};d.age = 40; // Modifying a property: No errorconsole.log(d); // { name: 'John Doe', age: 40};d.zipCode = '52534'; // Adding a property: No errorconsole.log(d); // { age: 40, name: "John Doe", zipCode: '52534; }d = { name: 'Mary Jane', age: 25}; // TypeError: Assignment to constant variable.As we can see above, we can modify and add properties to the object since this only modifies the contents of what the const variable is pointing to, but does not try to overwrite the contents of the const variable itself. However, if we try to update the binding of the const variable by re-assigning it a completely new object d = { name: 'Mary Jane', age: 25 };, it throws a TypeError. 正如我们在上面看到的，我们可以修改对象并向其添加属性，因为这只会修改const变量指向的内容，而不会尝试覆盖const变量本身的内容。 但是，如果我们尝试通过为const变量的绑定重新分配一个全新的对象d = { name: 'Mary Jane', age: 25 };来更新const变量的绑定d = { name: 'Mary Jane', age: 25 }; ，则抛出TypeError 。
我什么时候应该使用什么？ (When should I use what?)
JavaScript now has three kinds of variables, and a natural question is wondering when to use what. JavaScript现在具有三种变量，一个自然的问题是想知道何时使用什么。
After the introduction of block-scoped let , the usage of var is generally discouraged to avoid confusion with function level scope, accidental re-declarations, and hoisting bugs with undefined value. Unless you have a compelling reason to use function scope of var, use let. 在引入块作用域的let ，通常不建议使用var以避免与函数级别范围，意外的重新声明以及undefined值的错误的混淆。 除非您有充分的理由使用var函数范围，否则请使用let 。
Use const to hold values that are facts, such as const PI = 3.14, or values that should strictly remain unmodified for the entire execution of the program. 使用const可以保存事实值，例如const PI = 3.14 ，或者在整个程序执行期间应严格保持不变的值。
A common programming approach consists of developers starting off by declaring all variables with const , and progressively converting them to let variables if the need arises. Personally, I start with let variables, and convert them to const variables if I see the need. There is no set approach, and you should use what works best for your code. 一种常见的编程方法是，开发人员首先使用const声明所有变量，然后在需要时逐步将其转换为let变量。 就个人而言，我先从let变量开始，然后在需要时将它们转换为const变量。 没有固定的方法，您应该使用最适合您的代码的方法。
If you have time, I strongly suggest that you read the fictional piece again as it will cement the connections in your mind with the additional technical knowledge. 如果您有时间，我强烈建议您再次阅读该虚构的文章，因为它会通过其他技术知识使您的思维联系更加牢固。
Thank you for reading! I hope you learned something new, and I would love to receive feedback. 感谢您的阅读！ 希望您能学到新知识，也希望收到反馈。
References: 参考文献：
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/let https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Statements/const https://dmitripavlutin.com/variables-lifecycle-and-why-let-is-not-hoisted/ https://dmitripavlutin.com/variables-lifecycle-and-why-let-is-not-hoisted/ https://github.com/getify/You-Dont-Know-JS https://github.com/getify/You-Dont-Know-JS 翻译自: https://www.freecodecamp.org/news/javascripts-var-let-and-const-variables-explained-with-a-story-2038e3c6b2f9/var和let和const
展开全文
• var与let、const的区别在最新的 ES6 中，新添加了两个用于变量声明的关键字 let 和 const一、var声明的变量会挂载在window上，而let和const声明的变量不会：var a = 'a';console.log(a,window.a) //abc abclet b = '...
var与let、const的区别在最新的 ES6 中，新添加了两个用于变量声明的关键字 let 和 const一、var声明的变量会挂载在window上，而let和const声明的变量不会：var a = 'a';console.log(a,window.a) //abc abclet b = 'b';console.log(b,window.b) //b undefinedconst c = 123;console.log(c,window.c) //123 undefined二、var声明变量存在变量提升，let和const不存在变量提升1 console.log(a); // undefined  ==>  a已声明还没赋值【var a】，默认得到undefined值2 var a = 100;1 console.log(b); // Uncaught ReferenceError: b is not defined ==> 报错：找不到b这个变量2 let b = 10;1 console.log(c); // Uncaught ReferenceError: b is not defined ==> 报错：找不到b这个变量2 const c = 10;三、let和const声明形成块作用域1 {2     var a = 100;3     let b = 10;4 }5 console.log(a); // 1006 console.log(b)  // 报错：b is not defined  ===> 找不到b这个变量1 if(true){2     var a = 100;3     const c = 1;4 }5  console.log(a); // 1006  console.log(c)  // 报错：c is not defined  ===> 找不到c这个变量四、同一作用域下let和const不能声明同名变量，而var可以1 var a = 100;2 console.log(a); // 10034 var a = 10;5 console.log(a); // 101 let a = 100;2 let a = 10; //  控制台报错：Identifier 'a' has already been declared  ===> 标识符a已经被声明了。五、暂存死区1 var a = 100;2 if(1){3     a = 10;4     //在当前块作用域中存在a使用let/const声明的情况下，给a赋值10时，只会在当前作用域找变量a，5     // 而这时，还未到声明时候，所以控制台Error:a is not defined6     let a = 1;7 }六、const1 /*2 * 　　1、一旦声明必须赋值,不能使用null占位。3 * 　　2、声明后不能再修改4 * 　　3、如果声明的是复合类型数据，可以修改其属性5 * */67 const a = 'abc';89 const list = [];10 list[2] = 'abc';11 console.log(list);　　//  [empty × 2, "abc"]1213 const obj = {a:100};14 obj.a = 'abc';15 console.log(obj);　　// {a:'abc'}
展开全文
• 我们都知道在最新的 ES6 中，新添加了两个用于变量声明的关键字 let const，那么这两个我们以前经常使用的 var 有什么区别呢？今天我们就来看一下吧。​​变量声明初始化在比较它们的区别之前，我们先来看...
• var和let和constby Shirshendu Bhowmick 通过Shirshendu Bhowmick With the old JavaScript, we had only one way to declare a variable, and that was with var, like var x = 10. It will create a variable ...
• 一、var声明的变量会挂载在window上，而let和const声明的变量不会： 复制代码 var a = 100; console.log(a,window.a); // 100 100 let b = 10; console.log(b,window.b); // 10 undefined const c = 1; console....
• var声明变量存在变量提升，let和const没有 变量提升：在一开始的时候把所有的声明先执行 （JavaScript 中，函数及变量的声明都将被提升到函数的最顶部。） console.log(a) ------------undefined, a已声明还没赋值，...
• var与let、const的区别 ...一、var声明的变量会挂载在window上，而let和const声明的变量不会： var a = 'a'; console.log(a,window.a) //abc abc let b = 'b'; console.log(b,window.b) //b...
• var变量声明会引入了一个新的标识符 declaration，在 JavaScript 中，新创建的变量的默认值都是 undefined。 作用域 JavaScript 的世界共有两种作用域：全局作用域方法作用域。...var let ...
• 1.var和let比较 初始化 var和let未初始化的变量默认值都为undefined。 var a1; let a2; console.log(a1+"-"+a2) //undefined--undefined 作用域 var声明的变量作用域的范围为方法作用域，即整个花括号中。 ...
• var和变量提升 js代码是有两个步骤，先解释，后执行。在解释的过程中会将var声明的变量提升至当前作用域的最顶端，然后再一步步执行。 var elem = 'test'; if(elem){ console.log(elem); //test }else{ var str = ...
• 本博客用于个人学习使用，资料可能... var a = 10; console.log(a);//10 } console.log(a);//10 //在执行前会先进行变量提升，提升到全局作用域最顶层,实际执行代码如下： var a = undefined; { a = 10; console...
• let a = 10 console.log(a,window.a) //10 undefined const a = 10; console.log(a,window.a); // 10 undefined 2.var存在变量提升 console.log(a) // 10 var a = 10; console.log(a) // a is not defined l
• 我们都知道在最新的 ES6 中，新添加了两个用于变量声明的关键字 let const，那么这两个我们以前经常使用的 var 有什么区别呢？今天我们就来看一下吧。 变量声明初始化 在比较它们的区别之前，我们先来看...
• ES6之前一直用 var 来声明变量，在ES6中，常用 let  const 来声明，它们都是块级作用域；let 命令只在代码块有效，不允许重复声明；const 声明的变量是常量，它的值被设置后不能修改，所以一旦声明后必须...
• ES6===ECMAScript6 ECMAScript是一种由Ecma国际（前身为欧洲计算机制造商协会,...这种语言在万维网上应用广泛，它往往被称为JavaScript或JScript，但实际上后两者是ECMA-262标准的实现扩展。 目前各大浏览器基本上...
• 其用法类似于var，但是所声明的变量只在let命令所在的代码块内有效。 例如：for循环的计数器就很适合使用let命令。 for (let i=0;i<arr.length;i++){...} 2.ES6新增const用来声明常量。一旦声明，其值就...

...