// var - 函数作用域functionvarExample(){var x =1;if(true){var x =2;// 同一个 x
console.log(x);// 2}
console.log(x);// 2}// let - 块级作用域functionletExample(){let x =1;if(true){let x =2;// 不同的 x
console.log(x);// 2}
console.log(x);// 1}
1.2 循环中的块级作用域
// var 在循环中的问题for(var i =0; i <3; i++){setTimeout(()=> console.log(i),1);// 3, 3, 3}// let 在循环中的正确行为for(let i =0; i <3; i++){setTimeout(()=> console.log(i),1);// 0, 1, 2}
2. 不允许重复声明
2.1 同一作用域重复声明
// var 允许重复声明var x =1;var x =2;// 正常工作// let 不允许重复声明let y =1;let y =2;// SyntaxError: Identifier 'y' has already been declared// var 和 let 也不能重复声明var z =1;let z =2;// SyntaxError: Identifier 'z' has already been declared
2.2 不同作用域的声明
// 不同块级作用域可以声明同名变量let x =1;if(true){let x =2;// 正常工作
console.log(x);// 2}
console.log(x);// 1
3. 没有变量提升
3.1 var 的变量提升
console.log(x);// undefinedvar x =1;// 等同于var x;
console.log(x);
x =1;
3.2 let 的非提升特性
console.log(x);// ReferenceError: Cannot access 'x' before initializationlet x =1;// 函数中也是一样functionexample(){
console.log(x);// ReferenceErrorlet x =1;}
4. 暂时性死区(TDZ)
4.1 基本概念
// 在声明之前使用变量会导致 TDZ 错误{
console.log(x);// ReferenceErrorlet x =1;}
4.2 复杂场景中的 TDZ
// 函数参数中的 TDZfunctionexample(x = y, y =2){return[x, y];}example();// ReferenceError: y is not defined// 条件语句中的 TDZif(true){
console.log(x);// ReferenceErrorlet x =1;}
5. 不与顶层对象挂钩
5.1 var 与顶层对象的关系
// 浏览器环境var x =1;
console.log(window.x);// 1// Node.js 环境var y =1;
console.log(global.y);// 1
5.2 let 与顶层对象的隔离
// 浏览器环境let x =1;
console.log(window.x);// undefined// Node.js 环境let y =1;
console.log(global.y);// undefined
6. 实际应用场景
6.1 循环中的闭包
// 使用 var 的问题const buttons = document.querySelectorAll('button');for(var i =0; i < buttons.length; i++){
buttons[i].addEventListener('click',function(){
console.log('Button '+ i +' clicked');// 总是显示最后一个 i});}// 使用 let 的解决方案for(let i =0; i < buttons.length; i++){
buttons[i].addEventListener('click',function(){
console.log('Button '+ i +' clicked');// 正确显示当前按钮的索引});}