第二十九天:let 与 const — 告别 var 的时代
蜗牛往上爬 · 前端工业可视化学习笔记 第 29 篇
正式进入 ES6 标准学习!第一课:let/const。从今天起,我们几乎不再用var。let 带来块级作用域,const 带来不可变的引用——它们解决了 var 多年的两大痛点:作用域污染和变量提升陷阱。
目录
一、let:块级作用域
var 只有函数作用域,let 有块级作用域({} 内有效)。
// var 穿透块
{
var a = 10;
}
console.log(a); // 10
// let 不穿透块
{
let b = 20;
}
// console.log(b); // ❌ ReferenceError: b is not defined
为什么重要:if、for、while 的 {} 都会形成作用域,let 让临时变量不"泄漏"到外面,代码更干净。
二、TDZ:暂时性死区
// var 声明提升 → 访问不报错,只是 undefined
console.log(a); // undefined
var a = 10;
// let 有 TDZ → 声明前访问报错
// console.log(b); // ❌ ReferenceError: Cannot access 'b' before initialization
let b = 20;
TDZ(Temporal Dead Zone):从代码块开始到 let/const 声明之间的区域。这比 var 的"undefined 陷阱"更安全——错误尽早暴露。
三、不允许重复声明
// var 允许重复(后覆盖前)
var x = 1;
var x = 2; // ✅
// let 不允许
let y = 1;
// let y = 2; // ❌ SyntaxError
// 也不允许和函数参数重复
// function fn(a) { let a; } // ❌
四、const:只读常量
// 声明时必须赋值
// const a; // ❌ SyntaxError: Missing initializer
const MAX_TEMP = 80;
// MAX_TEMP = 90; // ❌ TypeError: Assignment to constant variable
// 和 let 一样:块级作用域 + TDZ + 不允许重复声明
命名约定:真正的常量(值永不改变)通常全大写 + 下划线,如 MAX_TEMP、API_URL。
五、const 的坑:内容可以改
const 锁住的是变量指向的地址,不是对象/数组的内容:
// 对象:改属性 ✅,重新赋值 ❌
const device = { name: "CNC-001", temp: 65 };
device.temp = 85; // ✅ 改内容
device.name = "CNC-002"; // ✅ 改内容
// device = { name: "X" }; // ❌ 换地址
// 数组:push/pop ✅,重新赋值 ❌
const devices = ["CNC-001"];
devices.push("AGV-002"); // ✅ 改内容
// devices = []; // ❌ 换地址
一句话:const 是"不能换引用",不是"不能改内容"。
六、var 的 for 陷阱与 let 的解法
这是 var 最经典的坑——闭包陷阱:
// var:三次都是 3
for (var i = 0; i < 3; i++) {
setTimeout(function () { console.log(i); }, 100);
}
// 输出:3 3 3
// let:每次循环都是独立的绑定
for (let j = 0; j < 3; j++) {
setTimeout(function () { console.log(j); }, 100);
}
// 输出:0 1 2
原理:
var:只有一份全局 i,回调执行时 i 已是 3let:每次循环创建独立的 j,回调捕获各自的值
这个坑在"批量给按钮绑定事件""定时器读取循环变量"等场景极其常见,用 let 直接解决。
七、实战:重构设备管理系统
把第 10 周的 ES5 代码升级为 ES6 声明方式:
// ===== ES5(旧)=====
var devices = [{ id: "CNC-001", name: "数控机床" }];
function render(filterText) {
var list = document.getElementById("device-list");
list.innerHTML = "";
var data = filterText
? devices.filter(function (d) { return d.name.indexOf(filterText) !== -1; })
: devices;
data.forEach(function (device) {
var li = document.createElement("li");
li.textContent = device.id + " - " + device.name;
list.appendChild(li);
});
}
// ===== ES6(新)=====
const devices = [{ id: "CNC-001", name: "数控机床" }];
function render(filterText) {
const list = document.getElementById("device-list");
list.innerHTML = "";
const data = filterText
? devices.filter(d => d.name.indexOf(filterText) !== -1) // 箭头函数
: devices;
data.forEach(device => {
const li = document.createElement("li");
li.textContent = `${device.id} - ${device.name}`; // 模板字符串
list.appendChild(li);
});
}
声明原则:
数据(devices)、DOM 元素(list)→
const(地址不变)循环变量(i)→
let(会变)基本不再用
var
八、总结
使用原则:默认 const,需要重新赋值时用 let,基本不用 var。
🎯 let/const 是 ES6 的地基。明天学解构赋值——最常用的新语法,让代码更优雅。