一、核心知识点(30 分钟吃透)
1. 作用域
- 全局作用域:变量在整个代码中可访问,挂载到 window(浏览器)/global(Node)上,易造成变量污染。
- 函数作用域:变量仅在函数内部可访问,函数执行完销毁。
- 块级作用域 (ES6 新增):由
{}包裹(if/for/while 等),let/const专属,解决变量泄露问题。
2. 变量提升
- var :声明提升到当前作用域顶部,赋值不提升(
console.log(a) // undefined; var a = 1)。 - let/const :存在 "暂时性死区(TDZ)",声明不会提升,在声明前访问直接报错(
console.log(b) // 报错; let b = 2)。
二、10 道手写练习题(40 分钟必练)
-
分析输出结果并解释: js
console.log(a); var a = 10; console.log(b); let b = 20; -
分析 for 循环输出: js
for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); // 输出? } // 改成let后输出? -
用 let 改造以下代码,避免变量污染: js
var flag = true; if (flag) { var name = "张三"; } console.log(name); // 想让这里报错,怎么改? -
声明常量 PI,确保不可修改: js
// 用const实现 -
解释为什么 const 声明的对象可以修改属性: js
const obj = { name: "李四" }; obj.name = "王五"; // 不报错,为什么? -
写出以下代码输出: js
function fn() { var x = 1; if (true) { var x = 2; } console.log(x); // 输出? } fn(); -
块级作用域实战:用 let 实现循环内绑定不同的事件: js
for (let i = 0; i < 3; i++) { document.querySelector(`.btn${i}`).onclick = () => { alert(i); }; } -
区分 var/let 声明的变量作用域: js
{ var m = 1; let n = 2; } console.log(m); // 输出? console.log(n); // 输出? -
暂时性死区案例分析: js
var c = 1; if (true) { c = 2; // 报错,为什么? let c; } -
用 const 声明数组并尝试修改,解释结果: js
const arr = [1,2,3]; arr.push(4); // 结果? arr = [5,6]; // 结果? <script> // **************** var、let、const 的区别和使用场景 **************** // 1.var 和 let 都是声明变量,但是有区别: // var 变量提升 console.log(a); //undefined var a = 10; // let 没有变量提升 console.log(b); //ReferenceError: b is not defined let b = 20; // 2.var 和 let 的作用域: // 因为 var 没有块级作用域,循环变量 i 没有被限制在循环块内,导致最终输出 3 3 3。 for (var i = 0; i < 3; i++) { setTimeout(() => { console.log(i); //3 3 3 }, 0); } // let 变量提升,循环变量 i 被限制在循环块内,最终输出 0 1 2。 for (let i = 0; i < 3; i++) { setTimeout(() => { console.log(i); //0 1 2 }, 0); } // 用 let 改造以下代码,避免变量污染 // var:没有块级作用域,if 块内声明的 name 会泄露到外部,所以 console.log(name) 能正常访问 var flag = true; if (flag) { var name = "张三"; } console.log(name); // 想让这里报错,怎么改? // let:有块级作用域,if 块内声明的 name 不会泄露到外部,所以 console.log(name) 报错 let flag2 = true; if (flag2) { let name = "张三"; console.log(name); // 张三 } console.log(name); // ReferenceError: name is not defined // 3.const 声明常量: // 声明常量 PI,确保不可修改: const PI = 3.1415926; console.log(PI); // 3.1415926 PI = 3; // TypeError: Assignment to constant variable. console.log(PI); // 3.1415926 // 解释为什么 const 声明的对象可以修改属性: const obj = { name: "zhangsan", age: 18 }; obj.name = "lisi"; console.log(obj); // {name: "lisi", age: 18} // const 只保证变量本身不能被重新赋值,不限制对象内部属性的修改。 // obj (常量引用) ────→ { name: 'zhangsan', age: 18 } // │ │ // │ 引用地址不可变 │ 属性值可修改 // ▼ ▼ // 不能指向新对象 可以修改内部属性 // 写出以下代码输出: function fn() { var x = 1; if (true) { var x = 2; } console.log(x); // 输出2 // 因为 var 没有块级作用域,if 块内的 x 变量覆盖了外部的 x 变量,所以最终输出 2。 } fn(); //4. 实际应用场景: // 块级作用域实战:用 let 实现循环内绑定不同的事件: for (let i = 0; i < 3; i++) { document.querySelector(`.btn${i}`).onclick = () => { alert(i); // 点击按钮弹出不同的提示框 }; // 这里的 i 变量被限制在循环块内,所以点击按钮时弹出不同的提示。 } //5.区分 var/let 声明的变量作用域: { var m = 1; let n = 2; } // var 声明的变量作用域是全局的,所以在函数外也可以访问到,输出 1。 console.log(m); console.log(n); // 输出?//ReferenceError: n is not defined // 6.暂时性死区案例分析: // ❌ 报错:暂时性死区 var c = 1; if (true) { c = 2; // ReferenceError let c; } // ✅ 正确:先声明后使用 var c = 1; if (true) { let c; c = 2; // 正常,修改的是块内变量 } console.log(c); // 1,外部变量未受影响 // ✅ 正确:不使用同名变量 var c = 1; if (true) { c = 2; // 正常,修改的是外部 var c // 没有 let c 声明 } console.log(c); // 2 //7.用 const 声明数组并尝试修改,解释结果: const arr = [1, 2, 3]; arr.push(4); // 正常,修改的是数组元素 arr=[5,6,7]; // TypeError: Assignment to constant variable. console.log(arr); // [1, 2, 3, 4] // 解释:const 声明的数组 arr 是一个常量引用,不能被重新赋值,所以不能修改数组元素。 </script>
三、核心面试题 + 标准答案(20 分钟背会)
面试题:var/let/const 的区别?
标准答案(高级工程师视角,精简且有深度):
-
作用域层面:
- var 是函数 / 全局作用域,无块级作用域,易造成变量泄露;
- let/const 是块级作用域 ,变量仅在
{}内有效,解决了 for 循环、if 判断中变量污染问题。
-
变量提升层面:
- var 存在变量提升,声明提升到作用域顶部,赋值不提升(声明前访问为 undefined);
- let/const 存在 "暂时性死区(TDZ)",声明不会提升,声明前访问直接报错,更符合编程直觉。
-
重复声明层面:
- var 允许同一作用域重复声明同一变量(后声明覆盖前声明);
- let/const 不允许同一作用域重复声明,重复声明直接报错,提升代码健壮性。
-
赋值层面:
- var/let 声明后可重新赋值;
- const 声明时必须初始化,且指向的内存地址不可修改(简单类型不可改,复杂类型如对象 / 数组可修改属性 / 元素),适合声明常量。
加分补充(体现工程化思维):
- 实际开发中,优先使用
const(约 80% 场景),仅在需要重新赋值时用let,彻底抛弃var; - const 能强制开发者思考变量是否需要修改,减少代码逻辑漏洞,也便于团队协作维护。
四、错题整理模板(10 分钟完成)
表格
| 错题类型 | 错误代码 | 错误原因 | 正确写法 / 知识点 |
|---|---|---|---|
| 变量提升 | console.log(b); let b=20 | 忽略暂时性死区 | let 声明前不可访问,需先声明再使用 |
| const 特性 | const arr = [1,2]; arr = [3,4] | 误解 const 不可修改数组 | const 仅锁定内存地址,数组 / 对象属性可改,重新赋值才报错 |
总结
- 核心考点 :var/let/const 的核心差异集中在作用域、变量提升、赋值规则三个维度,是前端基础高频面试题;
- 实战重点:开发中优先用 const,其次 let,彻底弃用 var,避免变量污染和逻辑漏洞;
- 易错点:const 并非 "常量不可变",而是 "引用地址不可变",复杂类型的属性 / 元素仍可修改。