《你不知道的 JavaScript(上卷)》第 3-4 章核心笔记:作用域与提升机制
作用域不是“变量在哪里声明”,而是“变量在哪里可被访问”。理解函数作用域、块作用域与变量提升,是掌握 JS 执行机制的关键。
一、函数作用域 vs 块作用域(第 3 章)
1. 函数作用域是传统主力
var声明的变量属于所在函数的作用域;- 函数内部可隐藏外部变量(避免污染全局);
- 模拟块作用域的经典技巧:IIFE(立即执行函数表达式)
(function() {
var a = 1; // 仅在 IIFE 内部可见
})();
console.log(a); // ReferenceError
2. 块作用域:ES6 的革命性补充
let/const引入真正的块级作用域({}内);- 常用于
if、for、while等语句块中; - 解决
var在循环中闭包的经典问题:
for (let i = 0; i < 3; i++) {
setTimeout(() => console.log(i), 100); // 输出 0,1,2(正确!)
}
// 若用 var,则输出 3,3,3
3. 其他块作用域形式
try...catch中的catch参数具有块作用域;with(已废弃)也曾创建作用域,但因性能与安全问题不推荐使用。
二、变量与函数提升(第 4 章)
1. 提升的本质
- JavaScript 不存在“先声明后使用”的运行时要求;
- 引擎在编译阶段将声明(
var、function)“移动”到作用域顶部; - 只有声明被提升,赋值/执行留在原地。
2. var 提升示例
console.log(a); // undefined(不是报错!)
var a = 2;
// 实际等价于:
var a;
console.log(a); // undefined
a = 2;
3. 函数提升优先级更高
- 函数声明(
function foo() {})会被完整提升(包括函数体); - 函数表达式(
var foo = function() {})仅提升变量名,值为undefined。
foo(); // ✅ 正常执行
bar(); // ❌ TypeError: bar is not a function
function foo() { console.log('声明式'); }
var bar = function() { console.log('表达式'); };
4. 函数与变量同名?函数胜出!
foo(); // "1"
var foo;
function foo() { console.log("1"); }
foo = function() { console.log("2"); };
// 编译后:function foo 被提升,覆盖 var foo
⚠️ 注意:在同一个作用域内重复
var声明会被忽略,但重复function声明会覆盖。
三、关键结论
- 作用域决定变量可见性,提升决定变量何时可用;
- 优先使用
let/const避免var的提升陷阱; - 函数声明提升 > 变量提升;
- 理解“编译阶段 vs 执行阶段”是破除 JS 执行迷思的核心。
📚 建议:不要依赖提升写代码!始终在作用域顶部显式声明变量,提升可读性与可维护性。