
3.4 let
var变量在JavaScript中是函数作用域。这与其他许多语言(C#、Java等)不同,它们的变量是块作用域。如果你将块作用域的思维带入JavaScript,你可能期望下面的代码会输出123,而不是456。

这是因为在if块内并没有创建一个新的变量作用域。变量foo在if块内外都是相同的(它在块外有一个相同的定义)。这是JavaScript编程中常见的错误来源,也是TypeScript和ES6推荐你在一个真实的块作用域内使用let来定义变量的原因。用let代替var,可以让你得到一个与外界变量相隔离的、真实的、唯一的元素,示例如下。

另一个使用let来避免错误的地方是循环。

我们发现,无论何时,使用let都会更好一些,因为它会给新的或现有的多语言开发人员带来更少的意外。
1.函数会创建新的作用域
除let外,如果我们想要证明,在JavaScript中函数也可以创建一个新的作用域,可以像下面这样做。

这种行为是你所期望的,如果没有它,在JavaScript中写代码将会非常困难。
2.生成JavaScript
在TypeScript编译生成的JavaScript中,只是简单地将let重命名为var(如果在周围的作用域内不存在相同的名称的话)。例如下面这个例子,只是将var替换成了let。

然而,如果变量的名称已经在周围作用域中被使用,那么就会创建一个新的变量名称,如下所示(注意foo_1)。

3.switch
你可以在{}中包装你的case,用来在不同的case状态中复用变量名称,示例如下。


4.闭包中的let
JavaScript开发者常见的一个面试题是,下面这段简单的代码会输出什么。

一个预期的答案是0,1,2,但令人惊讶的是这3个函数输出的都是3。
出现这个结果的原因是,所有这3个函数都是从外部作用域使用变量i的,在执行它们(即第2个循环)时,i的值将为3(这是第1个循环的终止条件)。
一个修复的方法是,在每个循环中创建一个新的变量。如前面所说,我们可以通过创建一个新的函数并立即执行它来创建一个新的变量作用域,即IIFE模式:(function(){/*body*/})();,示例如下。


在这里,函数关闭了局部变量(通常被命名为local)的访问(由此被称为闭包),并使用这个而不是循环变量i。
请注意,闭包会对性能产生影响(它们需要存储周围的状态)
在循环里的ES6的let关键字有同样的功能,示例如下。

使用let代替var,会在每个循环中创建一个变量i。
5.小结
let对绝大多数代码都非常有用。它可以极大地加强代码的可读性,并能降低发生错误的概率。