一、let命令
let命令用于声明变量,es6之前声明变量都是使用var命令,var命令存在很多弊端。
let命令的特点
1、不存在变量提升:
var声明的变量,在变量声明之前使用不会报错,值为undefined,这样逻辑上讲不过去的,let命令声明的变量就抛弃了这种奇怪的变量提升的现象。
// var
console.log(a) // 输出undefined
var a = 1
// let
console.log(b) // 报错
let b = 1
2、不允许重复声明
var的情况下,是可以重复声明同一个变量的,而在let声明的变量,如果重复声明会报错。
// var
var a = 1
var a = 10
console.log(a) // 10
// let
let b = 1
let b = 10 //报错
3、let命令会带来块级作用域
在es6之前,js是不存在块级作用域的,只分为全局作用域和函数作用域,这就导致一个变量泄露到全局,内层变量覆盖外层变量的情况,在es6出现之前,开发人员都是用匿名函数解决这个问题。
var i =100
for(var i = 0; i < 10; i++) {
var b = 5
}
//变量覆盖:这就是for循环里面的i变量覆盖了外面的i比那辆
console.log(i) // 10
//变量泄露:在for循环中定义的变量,在外部作用域也可以读取
console.log(b) // 5
有了es6之后,也就带来了块级作用域,解决了变量覆盖和变量泄露的问题,让变量只在当前作用域以及当前子孙作用域有效。
{
let i = 10
console.log(i) // 10
{
console.log(i) // 10
}
}
console.log(i) // 报错:i is not defined
有一个经典的闭包问题
for(var i = 0;i < 10; i++) {
var a = "button"+i
document.getElementById(a).onclick = alert(i)
}
// 我们想要的效果是,点击第一个button alert 1.....
//在页面中点击任何一个button alert都是10
在es6没出现之前是用闭包解决这个问题的
for(var i = 0;i < 10; i++) {
var a = "button"+i
(function(i) {
document.getElementById(a).onclick = alert(i)
}(i))
}
有了局部作用域之后
for(let i = 0;i < 10; i++) {
let a = "button"+i
document.getElementById(a).onclick = alert(i)
}
// 变量i是let声明的,当前的i只在本轮循环有效
//所以每一次循环的i其实都是一个新的变量
值得一提: for(let i = 0;i < 10; i++) {let i = ‘ddd’} 的代码块,for设置循环变量的部分是父作用域。大括号是子作用域。
4、暂时性死区
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
1、let不存在变量提升,var存在。
2、let变量有局部作用域,不会出现内层变量覆盖外层变量,内层变量泄露的问题。
3、let变量不能重复声明,会报错。
4、let变量存在暂时性死区问题。