let许可你声明一个作用域被限定在块级中的变量、语句或许表达式。与var关键字差别的是,它声明的变量只能是全局或许全部函数块的。
一 作用域
let声明的变量只能在其声明的块或子块中运用,这个和var很类似,二者之间最主要的区分在于var声明的变量的作用域是全部关闭函数。
// var
function testVar() {
var a = 0;
if (true) {
var a = 1;
console.log(a); // 输出1
}
console.log(a); // 输出1
}
// let
function testLet() {
let a = 0;
if (true) {
let a = 1;
console.log(a); // 输出1 (差别的变量)
}
console.log(a); // 输出0
}
小结
在testVar函数内里反复输出了1,var声明的变量的作用域是全部关闭函数,所以到if内里被赋值为1,末了都输出为1。
在testLet函数内里{},两个花括号相当于一个作用域,两个a在差别的作用域内里,所以不受影响。(运用let能够完整替代闭包)
二简化内部函数代码
比方给很多函数增加事宜
/*
* 运用let
*/
let lists = document.getElementsByTagName('li');
for (let i = 0; i < lists.length; i++) {
lists[i].onclick = function(ev) {
console.log(`点击了第${i}个元素`);
}
}
console.log(i); // 报错 Uncaught ReferenceError: i is not defined
运转这段代码点击每一个元素都能输出准确的i值,而且console报错
var lists = document.getElementsByTagName('li');
for (var i = 0; i < lists.length; i++) {
lists[i].onclick = function(ev) {
console.log("点击了第"+i+"个元素"); // 点击了第6个元素
}
}
console.log(i); // 输出6
// 解决办法,能够运用自实行函数
var lists = document.getElementsByTagName('li');
for (var i = 0; i < lists.length; i++) {
(function(i){
lists[i].onclick = function(ev) {
console.log("点击了第"+i+"个元素"); // 一般输出
}
})(i);
}
console.log(i); // 输出6
上面的代码能够看出不管点击哪一个元素都是输出“点击了第6个元素”,而且末了console也是6。
小结
由于(匿名)内部函数的五个实例引用了变量i的五个差别实例。注重,假如你将let替换为var,则它将没法一般事情,由于一切内部函数都将返回雷同的i:6的最终值。另外,我们能够经由过程将建立新元素的代码移动到每一个轮回的作用域来坚持轮回更清楚。
三 暂存死区的毛病
不能再雷同函数和雷同作用域内里从新声明同一个变量
{
let a;
let a; //Uncaught SyntaxError: Identifier 'a' has already been declared
}
let 绑定不受变量提拔的束缚,也就是let声明不会被提拔到当前实行上下文的顶部,假如你在初始化之前引用它,也会报上面谁人毛病。
{
console.log(a); // Uncaught ReferenceError: a is not defined
let a;
let b;
}
上面引见了es6作用域的题目,表达式(2 + 55)内的标识符“a”会剖析为if块的a,而不是掩盖值为2的a。if块的a已生明,并未初始化,它仍处在暂存死区
function test(){
var a = 2;
if (true) {
let a = (a + 55); // ReferenceError
}
}
test();
小结
当在块中运用时,let将变量的作用域限定为该块。注重var的作用域在它被声明的函数内的区分。
总结
- let有块级作用域;
- 没有变量提拔;
- 暂存死区的毛病;
- 不能反复声明;
- do表达式。
— 参考阮先生的 《ECMAScript 6 入门》