变量声明:let 与 const
🎯 引言
通过这篇文章,你能够清楚地理解 ES6 中的 let 和 const 与传统的 var 之间的区别。在实际开发中,你会知道什么时候用 let,什么时候用 const,以及它们在作用域和变量提升上的表现。同时,你还会搞明白 const 声明的对象到底可不可变,从而避免常见的错误。掌握这些基础知识,会让你的 JavaScript 代码更规范、更安全。
🧱 作用域大揭秘:函数作用域 vs 块级作用域
在 JavaScript 里,作用域决定了变量可以在哪些地方被访问。我们先回顾一下传统的 var:
function testVar() {
if (true) {
var a = 10;
}
console.log(a); // 10,var 声明变量没有块级作用域
}
testVar();
这里,虽然变量 a 是在 if 的代码块里声明的,但它能在整个函数里访问。这是因为 var 有函数作用域,它忽略代码块,只要在函数里就能访问。
而 let 和 const 则不一样:
function testLet() {
if (true) {
let b = 20;
}
console.log(b); // 报错,b 在 if 块外不能访问
}
testLet();
let 和 const 拥有块级作用域,也就是说它们只在代码块 {} 内有效。块级作用域更符合我们日常思考的逻辑,比如在循环、条件判断时,变量只在块内生效,出了块就“消失”了,不会污染外层作用域。
🌄 变量提升对比:var 的“魔法”与 let、const 的“限制”
变量提升是 JavaScript 的一个奇妙现象,说白了就是变量声明会被提前到当前作用域的顶部。这意思是你可以在声明变量之前用它(虽然不推荐这样写)。
console.log(x); // undefined
var x = 5;
上面代码中,var x 被提升了,但赋值 =5 并没有提升,所以输出是 undefined,而不是报错。
但是,用 let 或 const 就不一样了:
console.log(y); // 报错,不能在声明前访问
let y = 10;
使用 let 和 const 声明的变量会进入“暂时性死区”(Temporal Dead Zone,简称 TDZ),在声明前访问会报错。这其实是语言设计上的一种保护机制,避免你乱用未初始化的变量。
📌 let 和 const 的本质区别
虽然 let 和 const 都有块级作用域和不会变量提升的特性,但它们的主要区别是:
- let 声明的变量可以重新赋值
- const 声明的变量一旦赋值后不能修改引用(不能重新赋值)
来看个例子:
let age = 25;
age = 30; // 正常,let 支持重新赋值
const name = 'Alice';
name = 'Bob'; // 报错,const 不允许重新赋值
如果你确定一个变量的值不会被修改,一定要用 const,这样可以避免意外改动,让代码更安全和易维护。
const 声明变量,只有在变量需要被重新赋值时再使用 let🧩 const 声明的对象是否可变?
这里是很多人容易误解的地方。const 并不意味着值完全不可变,而是变量的“引用”不可变。
举个生活中的例子:想象你有一个固定的信箱号码(const 变量名),这个信箱号码不能改,但你可以往信箱里放不同的信件(对象的属性可以改变)。
const person = {
name: 'Tom',
age: 18,
};
person.age = 20; // 合法,修改对象属性
person.name = 'Jerry'; // 也合法
person = {}; // 报错,不能给常量重新赋值
所以,const 保护的是变量的“地址”,但对象本身的内容是可以被修改的。
Object.freeze(),它可以冻结对象,阻止属性被修改。const person = Object.freeze({
name: 'Tom',
age: 18,
});
person.age = 20; // 不生效,属性无法被修改
console.log(person.age); // 18
🎉 实战小例子
让我们用一个简单的例子来演示 let 和 const 的正确使用场景。
function showScores() {
const scores = [90, 80, 70];
for (let i = 0; i < scores.length; i++) {
// i 用 let 声明,保证每次循环 i 都是块级作用域
console.log('Score ' + i + ': ' + scores[i]);
}
// scores 是 const,不能赋值新数组,不过可以修改数组内容
scores.push(85);
console.log(scores);
}
showScores();
这里,scores 用 const 定义,保证我们不会误赋予它新的数组;i 用 let 定义,是因为循环计数器需要在每次循环中更新。
🧾 小节总结
- let 和 const 有块级作用域,var 只有函数作用域,避免了变量被意外访问或污染。
- var 会变量提升,访问未赋值变量会得到 undefined;let 和 const 有暂时性死区,提前访问会报错。
- const 声明的变量不能重新赋值,但如果它是对象,属性是可以修改的。
- 想让对象内容不可变,可以用 Object.freeze。
❓ 知识问答(Q&A)
Q:var、let 和 const 之间最大的区别是什么?
A:var 有函数作用域且会变量提升,let 和 const 有块级作用域且不会变量提升;const 还不能重新赋值。
Q:为什么访问 let 或 const 声明的变量在声明前会报错?
A:因为它们存在暂时性死区,防止变量在初始化之前被使用。
Q:const 声明的对象能修改属性吗?
A:可以,const 只保证变量引用不变,属性内容是可以修改的。
🧪 小练习
- 写一个函数,使用 let 声明一个计数器,循环打印数字 1 到 5。
function printNumbers() {
// 在这里写代码
}
printNumbers();
- 使用 const 声明一个对象,尝试更改它的属性,再尝试重新赋值,观察结果。
const car = {
brand: 'Toyota',
year: 2020,
};
// 在这里尝试修改 car 的属性和重新赋值
🎉 恭喜你已经掌握 let、const、作用域及变量提升技能啦!这些都是写好前端代码的基础,持续练习,写出更高质量的 JS 代码吧!
