1. 块级作用域
1.1 let vs var 作用域对比
function varExample() {
var x = 1;
if (true) {
var x = 2;
console.log(x);
}
console.log(x);
}
function letExample() {
let x = 1;
if (true) {
let x = 2;
console.log(x);
}
console.log(x);
}
1.2 循环中的块级作用域
for (var i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 1);
}
2. 不允许重复声明
2.1 同一作用域重复声明
var x = 1;
var x = 2;
let y = 1;
let y = 2;
var z = 1;
let z = 2;
2.2 不同作用域的声明
let x = 1;
if (true) {
let x = 2;
console.log(x);
}
console.log(x);
3. 没有变量提升
3.1 var 的变量提升
console.log(x);
var x = 1;
var x;
console.log(x);
x = 1;
3.2 let 的非提升特性
console.log(x);
let x = 1;
function example() {
console.log(x);
let x = 1;
}
4. 暂时性死区(TDZ)
4.1 基本概念
{
console.log(x);
let x = 1;
}
4.2 复杂场景中的 TDZ
function example(x = y, y = 2) {
return [x, y];
}
example();
if (true) {
console.log(x);
let x = 1;
}
5. 不与顶层对象挂钩
5.1 var 与顶层对象的关系
var x = 1;
console.log(window.x);
var y = 1;
console.log(global.y);
5.2 let 与顶层对象的隔离
let x = 1;
console.log(window.x);
let y = 1;
console.log(global.y);
6. 实际应用场景
6.1 循环中的闭包
const buttons = document.querySelectorAll('button');
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function() {
console.log('Button ' + i + ' clicked');
});
}
for (let i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function() {
console.log('Button ' + i + ' clicked');
});
}
6.2 模块封装
{
let privateData = 'secret';
function doSomething() {
console.log(privateData);
}
window.api = { doSomething };
}
7. 最佳实践
7.1 推荐用法
let count = 0;
count++;
for (let i = 0; i < array.length; i++) {
}
if (condition) {
let temp = calculate();
}
7.2 避免的模式
function wrong() {
console.log(x);
let x = 1;
}
let x = 1;
let x = 2;
var y = 1;
let y = 2;
8. 与 const 的对比
8.1 基本区别
let x = 1;
x = 2;
const y = 1;
y = 2;
8.2 对象属性
let obj1 = { a: 1 };
obj1.a = 2;
const obj2 = { a: 1 };
obj2.a = 2;
obj2 = {};