暂时性死区
上篇文章我们了解到了let和var之间的细微差别,同时它们之间还有一个区别就是let声明的变量不会在作用域中被提升
<script> //name会被提升 console.log(name); //undefined var name = "Matt"; //age不会被提升 console.log(age); //ReferenceError age未定义 let age = 26 ; </script>
浏览器在解析代码的时候,JavaScript引擎也会注意出现在块后面的let声明,只不过在此之前不能以任何方式来引用未声明的变量,在let声明之前的之星瞬间都被称为暂时性死区,在此阶段引用任何后面才声明的变量都会抛出ReferenceError
全局声明
与var关键字不同,使用let在全局作用域中声明的变量不会成为window对象的属性(var声明的变量会)
<script> var name = 'Matt'; console.log(window.name); // 'Matt' let age = 26 ; console.log(window.age); // undefined </script>
let声明是在全局作用域里面发生的,响应变量会在页面的生命周期内存续,为了避免SyntaxError,我们必须确保页面不会重复声明同一个变量
条件声明
我们在使用var声明变量的时候,由于声明会被提升,JavaScript引擎会自动将多余的声明在作用域顶部合并为一个声明,因为let的作用域是块,所以不可能检查前面是否已经使用let声明过同名变量,同时也就不可能在没有声明的情况下使用它
<script> var name = 'Nicholas' let age = 26; </script>
注意注意注意!!!
对于let这个新的ES6关键字,不能依赖条件声明模式
不能使用let进行条件式声明是件好事,因为条件声明是一种反模式,它让程序变得更难理解
for循环中的let声明
在let出现之前,for循环定义的迭代变量会渗透到循环体外部
<script> for(var i = 0 ; i < 5 ; ++i){ //逻辑循环 } console.log(i); </script>
如果我们改成使用let,这个问题将会迎刃解决,因为迭代变量的作用域仅适用于for循环块内部
<script> for(let i = 0 ; i < 5 ; ++i){ //逻辑循环 } console.log(i); //ReferenceError: i没有定义 </script>
我们在使用var的时候,最常见的问题就是对迭代变量的奇特声明和修改
<script> for(var i = 0 ; i < 5 ; ++i ){ setTimeout(() => console.log(i),0); // 5 5 5 5 5 } </script>
之所以会这样,是因为退出循环的时候,迭代变量保存的都是循环退出的值:5。在执行超过逻辑时,所有的i都是同一个变量,因而输出的都是同一个最终值
而在使用let声明迭代变量的时候,JavaScript引擎在后台会为每个迭代循环声明一个新的迭代变量,每个setTimeout引用的都是不同的变量实例
<script> for(var i = 0 ; i < 5 ; ++i ){ setTimeout(() => console.log(i),0); // 1 2 3 4 5 } </script>