JavaScript: JavaScript 变量
变量是装数据的盒子——你给盒子贴个名字标签,随时往里放数据、取数据、换数据。
1. 什么是变量
想象你有一排贴着标签的盒子:一个叫"姓名"装着"张三",一个叫"年龄"装着 25。盒子里的东西可以换,标签不变——这就是变量。
在 JS 中,你用声明关键字(var / let / const)创建变量,用等号赋值:
HTML
<script>
var name = "张三";
let age = 25;
const PI = 3.14;
</script>
▶ 示例
JAVASCRIPT
// 本节代码示例
const message = "你好,世界!";
console.log(message);
这是最简单的示例,后续章节会详细解释。## 2. var 的问题
var 是 ES6 之前唯一的声明方式,它有两个让人头疼的特性:
- 函数作用域——在
if或for里用var声明的变量,外面也能访问到,这不符合直觉 - 变量提升——
var声明会被"提升"到作用域顶部,赋值不会提升。你可以在声明前使用变量(值为undefined),不会报错但容易误判
这两个特性让 var 成为 bug 的温床。现代 JS 中,var 基本已经被 let 和 const 取代。
3. let — 块级作用域,推荐首选
let 在 ES6(2015)中引入,修复了 var 的两个问题:
- 块级作用域——只在
{}内有效,出了块就访问不到 - 不存在变量提升——在声明前使用会直接报错(暂时性死区)
日常开发中,需要重新赋值的变量用 let。
4. const — 常量,不可重新赋值
const 也是块级作用域,但声明时必须赋值,且之后不能再重新赋值。
注意:const 限制的是"不能重新赋值",不是"不能修改"。如果 const 装的是对象或数组,你可以修改对象属性或数组元素,只是不能把这个变量指向另一个对象。
能用 const 就用 const,需要变的时候再用 let——这是最佳实践。
5. 变量命名规则
- 以字母、下划线
_或美元符$开头 - 后面可以跟字母、数字、下划线、美元符
- 不能以数字开头
- 不能使用 JS 关键字(
var、let、function等) - 推荐驼峰命名法:
firstName、totalPrice
6. 同时声明多个变量
你可以用逗号分隔,一次性声明多个变量:
HTML
<script>
let a = 1, b = 2, c = 3;
</script>
不过为了可读性,建议每行一个变量。
▶ 示例:var 的变量提升和函数作用域
HTML
📖 仅展示
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>JS 变量 - var 的问题</title>
<style>
body { font-family: "Microsoft YaHei", sans-serif; max-width: 550px; margin: 60px auto; }
.warn { background: #fff3e0; padding: 12px; border-radius: 8px; color: #E65100; border-left: 4px solid #FF9800; margin: 12px 0; }
.result { background: #f5f5f5; padding: 16px; border-radius: 8px; font-family: Consolas, monospace; line-height: 1.8; margin: 12px 0; }
button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; color: #fff; background: #FF9800; margin: 6px; }
button:hover { background: #F57C00; }
</style>
</head>
<body>
<h2>var 的问题演示</h2>
<p class="warn">⚠️ var 有变量提升和函数作用域问题,实际开发中避免使用</p>
<button id="hoistBtn">演示:变量提升</button>
<button id="scopeBtn">演示:函数作用域泄漏</button>
<div class="result" id="output">点击按钮查看结果</div>
<script>
document.getElementById("hoistBtn").onclick = function() {
var output = "";
output += "使用 var 声明前访问:x = " + typeof x + "\n";
var x = 10;
output += "声明后访问:x = " + x + "\n\n";
output += "👆 变量提升导致声明前不报错,值为 undefined\n";
output += "这在大型项目中很容易引发 bug!";
document.getElementById("output").textContent = output;
};
document.getElementById("scopeBtn").onclick = function() {
var output = "";
for (var i = 0; i < 3; i++) {
// var i 泄漏到循环外部
}
output += "循环结束后,i = " + i + "\n\n";
output += "👆 var i 泄漏到循环外部了!\n";
output += "如果用 let i,循环外就访问不到";
document.getElementById("output").textContent = output;
};
</script>
</body>
</html>
▶ 示例:let 的块级作用域
HTML
📖 仅展示
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>JS 变量 - let 块级作用域</title>
<style>
body { font-family: "Microsoft YaHei", sans-serif; max-width: 550px; margin: 60px auto; }
.good { background: #e8f5e9; padding: 12px; border-radius: 8px; color: #2E7D32; border-left: 4px solid #4CAF50; margin: 12px 0; }
.result { background: #f5f5f5; padding: 16px; border-radius: 8px; font-family: Consolas, monospace; line-height: 1.8; margin: 12px 0; }
button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; color: #fff; background: #4CAF50; margin: 6px; }
button:hover { background: #388E3C; }
</style>
</head>
<body>
<h2>let 块级作用域演示</h2>
<p class="good">✅ let 有块级作用域,出了 {} 就访问不到,更安全</p>
<button id="letScopeBtn">演示:let 块级作用域</button>
<button id="letLoopBtn">演示:let 在循环中</button>
<div class="result" id="output">点击按钮查看结果</div>
<script>
document.getElementById("letScopeBtn").onclick = function() {
let output = "块级作用域测试:\n";
let x = 100;
output += "外层 x = " + x + "\n";
{
let x = 200;
output += "内层 x = " + x + "\n";
}
output += "出块后 x = " + x + "\n\n";
output += "👆 内外层的 x 互不影响,各自独立";
document.getElementById("output").textContent = output;
};
document.getElementById("letLoopBtn").onclick = function() {
let output = "let 在循环中:\n";
for (let i = 0; i < 3; i++) {
output += "循环内 i = " + i + "\n";
}
output += "\n";
try {
output += "循环外 i = " + i;
} catch(e) {
output += "循环外访问 i → 报错:" + e.message;
}
output += "\n\n👆 let i 被限制在循环内,不会泄漏到外部";
document.getElementById("output").textContent = output;
};
</script>
</body>
</html>
▶ 示例:const 常量
HTML
📖 仅展示
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>JS 变量 - const 常量</title>
<style>
body { font-family: "Microsoft YaHei", sans-serif; max-width: 550px; margin: 60px auto; }
.tip { background: #e3f2fd; padding: 12px; border-radius: 8px; color: #1565C0; border-left: 4px solid #2196F3; margin: 12px 0; }
.result { background: #f5f5f5; padding: 16px; border-radius: 8px; font-family: Consolas, monospace; line-height: 1.8; margin: 12px 0; }
button { padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; color: #fff; margin: 6px; }
#constBtn { background: #9C27B0; }
#objectBtn { background: #2196F3; }
</style>
</head>
<body>
<h2>const 常量演示</h2>
<p class="tip">💡 const 声明后不能重新赋值,但对象和数组的属性/元素可以修改</p>
<button id="constBtn">演示:const 不可重赋值</button>
<button id="objectBtn">演示:const 修改对象属性</button>
<div class="result" id="output">点击按钮查看结果</div>
<script>
document.getElementById("constBtn").onclick = function() {
const PI = 3.14159;
let output = "const PI = " + PI + "\n\n";
output += "尝试重新赋值 PI = 3.14:\n";
try {
PI = 3.14;
} catch(e) {
output += "❌ 报错:" + e.message;
}
output += "\n\n👆 const 变量一旦赋值就不能再改";
document.getElementById("output").textContent = output;
};
document.getElementById("objectBtn").onclick = function() {
const person = { name: "张三", age: 25 };
let output = "const person = " + JSON.stringify(person) + "\n\n";
output += "修改 person.age = 26:\n";
person.age = 26;
output += "person = " + JSON.stringify(person) + "\n\n";
output += "添加 person.city = '北京':\n";
person.city = "北京";
output += "person = " + JSON.stringify(person) + "\n\n";
output += "👆 const 限制的是变量指向,不是对象内容\n";
output += "就像 const 盒子锁定了标签,但盒子里东西可以换";
document.getElementById("output").textContent = output;
};
</script>
</body>
</html>
▶ 示例:var / let / const 对比
HTML
📖 仅展示
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>JS 变量 - 三种声明对比</title>
<style>
body { font-family: "Microsoft YaHei", sans-serif; max-width: 600px; margin: 60px auto; }
table { width: 100%; border-collapse: collapse; margin: 16px 0; }
th, td { padding: 10px; text-align: center; border: 1px solid #ddd; }
th { background: #2196F3; color: #fff; }
.bad { color: #f44336; }
.good { color: #4CAF50; font-weight: bold; }
button { margin-top: 12px; padding: 10px 24px; font-size: 16px; border: none; border-radius: 6px; cursor: pointer; color: #fff; background: #e91e63; }
#result { margin-top: 12px; padding: 16px; background: #f5f5f5; border-radius: 8px; font-family: Consolas, monospace; line-height: 1.8; }
</style>
</head>
<body>
<h2>var / let / const 对比</h2>
<table>
<tr><th>特性</th><th>var</th><th>let</th><th>const</th></tr>
<tr><td>作用域</td><td class="bad">函数作用域</td><td class="good">块级作用域</td><td class="good">块级作用域</td></tr>
<tr><td>变量提升</td><td class="bad">是(值为undefined)</td><td class="good">否(暂时性死区)</td><td class="good">否(暂时性死区)</td></tr>
<tr><td>可否重新赋值</td><td class="bad">是</td><td>是</td><td class="bad">否</td></tr>
<tr><td>声明前使用</td><td class="bad">不报错</td><td class="good">报错</td><td class="good">报错</td></tr>
<tr><td>推荐程度</td><td class="bad">避免使用</td><td class="good">推荐</td><td class="good">首选</td></tr>
</table>
<button id="testBtn">运行对比测试</button>
<div id="result"></div>
<script>
document.getElementById("testBtn").onclick = function() {
var output = "=== 对比测试 ===\n\n";
output += "【var】函数作用域:\n";
for (var i = 0; i < 3; i++) {}
output += "循环外 var i = " + i + "(泄漏了)\n\n";
output += "【let】块级作用域:\n";
for (let j = 0; j < 3; j++) {}
try {
output += "循环外 let j = " + j;
} catch(e) {
output += "循环外访问 let j → " + e.message + "(正确行为)";
}
output += "\n\n【const】不可重赋值:\n";
const MAX = 100;
output += "const MAX = " + MAX + "\n";
try {
MAX = 200;
} catch(e) {
output += "重赋值 → " + e.message + "(正确行为)";
}
output += "\n\n结论:const > let >> var";
document.getElementById("result").textContent = output;
};
</script>
</body>
</html>
❓ 常见问题
Q const 声明的对象属性可以修改,那 const 有什么意义?
A const 保证变量指向不变——你不会意外地把
person 重新指向另一个对象,但修改已有对象的属性是合理的。就像你锁定了盒子上的标签(这个盒子永远叫"张三的盒子"),但往盒子里放什么、换什么都可以。Q 什么时候用 let,什么时候用 const?
A 简单判断法:声明时问自己"这个值以后会变吗?"——不会就用 const,会变就用 let。比如计数器用 let,配置常量用 const。绝大多数场景 const 就够了,你会发现自己用 const 的频率远高于 let。
Q var 完全不能用吗?
A 技术上能用,但没必要。let 和 const 是 var 的全面升级版,没有任何场景必须用 var 而不能用 let/const。老代码里看到 var 能看懂就行,新代码一律用 let/const。
📖 小节
- 变量是装数据的盒子,用声明关键字 + 变量名 + 赋值来创建
var有函数作用域和变量提升问题,现代 JS 中应避免使用let有块级作用域,不存在变量提升,需要重新赋值时使用const有块级作用域且不可重新赋值,声明时必须赋值const不能重新赋值,但对象/数组的属性和元素可以修改- 选择优先级:const 优先,let 其次,var 避免
📝 作业
- 基础题:用
const声明一个常量SITE_NAME赋值为你的名字,用let声明一个变量visitCount赋值为 0,然后在页面上显示这两个值。 - 进阶题:创建一个页面,用一个按钮模拟"访问计数"——每次点击按钮让
visitCount加 1 并显示当前值,体会 let 可重新赋值而 const 不行的区别。 - 挑战题:创建一个页面,用
const声明一个学生对象{ name: "张三", scores: [80, 90, 75] },然后实现:添加一个新成绩 85、计算平均分、修改名字为"李四",全程 const 不变,验证对象内容可以修改。