在ES6中新增加了 let,let 和 var 的用法类似,都是用以声明变量。
let声明变量的方式也和var类似,声明变量或是声明变量并附初始值。
let a; let b,c,d; let e = 100; let f = 251;g = 'qq',h = [];
let的特性:
变量不可重复声明、有块级作用域、不存在变量提升、暂时性死区、不影响作用域链
1、变量不可重复声明
在同一个作用域中,与var 不同的是,不可以使用let重复声明同一个变量
function qq(){ var a = 11; let a = 22; } // SyntaxError:Identifier 'a' has already been declared(标识符a已经被声明)
function qq(){ let a = 11; let a = 22; } //SyntaxError: Identifier 'a' has already been declared(标识符‘a‘已经被重复声明)
使用var 声明变量的时候就不会出现重复声明报错的问题可以重复声明,但是使用let 可以防止变量命名的重复,防止变量污染。
2、块级作用域
作用域包括:全局作用域、函数作用域、eval
let声明的变量有块级作用域,其声明的变量,只在let 命令所在的代码块内有效。
块级作用域:在代码块内有效,在代码块外无效。if、else、for等后面的 { }
{ var a = 11; let b = 22; } console.log(a); //11 console.log(b); //ReferenceError: a is not defined.
在代码块的范围内分别用 let和var声明了两个变量,因为var没有块级作用域,所以在代码块外面调用a,可以正常的返回a的值。
在代码块外面调用b,因为let有块级作用域所以会报错。
3、不存在变量提升
在声明var的时候会存在变量提升,但是let 不存在像 var那样会发生变量提升。所以使用 let 声明变量的时候,一定要在声明之后使用。
console.log(aa); //返回undefined console.log(bb); //报错 ReferenceError var aa = 11; var bb = 22;
使用 var 声明的 aa,则会发生变量声明,代码运行的时候就相当于在最前面声明了变量但是并没有赋值,所以最终会输出undefined。而用 let声明的 bb,则不会发生变量提升,在声明变量之前,该变量都是不存在的,如果在前面调用bb,就会返回error。
4、不影响作用域链
{ let aa = 'ww'; function fn() { console.log(aa); } fn(); } //结果输出 'ww'
在函数作用域中没有查找到 aa,则就会向上级查找aa,发现已经声明赋值的aa,所以最后返回结果 ww
5、暂时性死区
只要块级作用域内部存在 let 命令,它所声明的变量就会绑定(binding)这个区域,不受外界的影响。
var aa = 111; if (true) { aa = 'ww'; // ReferenceError let aa; }
上面代码中,有着全局变量 aa,但是在块级作用域内部 let 又声明了一个局部变量 aa。let声明的这个变量只在块级作用域内有效,绑定了这个块级作用域,所以在 let 声明变量之前对 aa 赋值则会报错。
在ES6中明确规定,如果区块中存在着let 和 const 命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。所以在代码块中,使用let 命令声明变量之前,该变量都是不可用的。这在语法上称为 “暂时性死区” (temporal dead zone,简称 TDZ)
ES6 规定怎实行死区和 let、const 不出现变量提升,只要是为了减少运行时的错误,防止在变量声明之前就使用这个变量,从而导致意外行为,有了这种规定之后,就可以很容易地规避这种错误。
总结来说,暂时性死区的本质就是,只要已进入当前作用域,所需要使用的变量已经存在了,但是无法获取(即不会发生变量提升提升)只有等到声明变量代码出现的时候,才可以正常地使用这个变量。
let实例:
在这个例子中想实现的效果是点击方块后改变其背景颜色为粉色。
注意 for循环计数器
因为let 存在块级作用域等特点,所以for 循环计数器,非常适合使用 let开声明变量。
for(let i = 0;i<=3;i++){ console.log(i); // 1、2、3 }; console.log(i); //ReferenceError: i is not defined
使用let 声明的变量 i ,只在 for 循环体内部有效,在for循环体外调用就会报错。
使用var 在for循环中,最后输出的还是4 。因为变量 i 是由var 声明的,因为var没有块级作用域,所以i 是直接存在全局中的,每一次循环,新的 i 值都会覆盖旧的值,所以最后输出的 i 值是经过更新表达式更新之后的值4。
var a = []; for(let i = 0;i<=3;i++) { a[i] = function() { console.log(i); }; } a[2](); //4 console.log(i); //4
但是如果使用的是 let声明,由于块级作用域的存在,当前的i 也只是在本循环内有效,每次循环的 i 都是一个新的变量,所以最后输出的是2。(如下所示)
var a = []; for(let i = 0;i<=3;i++) { a[i] = function() { console.log(i); }; } a[2](); //2
了解了 let 的特性之后,所以在本例中使用 let更为合理,使用 var 则会报错。
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 <title>let案例</title> 7 <style> 8 .container{ 9 width: 500px; 10 height:400px; 11 margin:100px auto; 12 color:#999; 13 } 14 .page-header{ 15 font-size:30px; 16 padding:10px; 17 border-bottom:1px solid #999; 18 margin-bottom:20px; 19 } 20 .item{ 21 margin-right:10px; 22 float:left; 23 width:100px; 24 height:50px; 25 border:2px solid teal; 26 } 27 </style> 28 </head> 29 <body> 30 <div class='container'> 31 <h2 class='page-header'>点击切换颜色</h2> 32 <div class="item"></div> 33 <div class="item"></div> 34 <div class="item"></div> 35 </div> 36 <script> 37 // 获取div元素对象 38 let items = document.getElementsByClassName('item'); 39 // 遍历并且绑定事件 40 for(let i = 0 ; i < items.length ; i++){ 41 // 如果使用的是var,var没有块级作用域,在for循环中的var实际上还是在全局作用域中。 42 items[i].onclick = function() { 43 // 修改当前元素的背景颜色 44 items[i].style.background = 'pink'; 45 } 46 } 47 console.log(i); 48 </script> 49 </body> 50 </html>
样式和实现效果:
点击之后: