块级作用域由大括号{}与let/const声明共同触发;仅{}或仅let/const均不构成块级作用域;let/const将变量绑定到最近的外层{},形成严格限制的生命周期和嵌套可见性规则。

块级作用域不是“自动存在”的,而是由 大括号 {} + let/const 声明 共同触发的。只有一对花括号,但里面用 var 声明变量,就**不构成块级作用域**;反过来,let 或 const 写在函数外、全局作用域里,也**不会凭空造出新块**——关键在于两者配合。
大括号是作用域的物理边界
任何成对的 {} 都算一个代码块,比如:
if (true) { ... }for (let i = 0; iwhile (x > 0) { ... }- 甚至单独写一个
{ let a = 1; console.log(a); }
这些 {} 本身只是语法结构,它是否成为“块级作用域”,取决于里面有没有用 let 或 const 声明变量。
let/const 是作用域的激活开关
let 和 const 的声明行为会把变量绑定到**最近的、包裹它的 {} 块**中。例如:
if (true) {
let x = 10;
const y = 'hello';
}
console.log(x); // ReferenceError
console.log(y); // ReferenceError
因为 x 和 y 的生命周期被严格限制在那个 if 的 {} 内,出了这个花括号就不可见。
注意:var 在同样位置声明,x 仍可在外部访问——它只会被提升到函数或全局作用域,完全无视 {}。
嵌套块中变量的可见性有层次
块可以嵌套,内部块能读取外部块的 let/const 变量,前提是没被同名变量遮蔽:
{ // 外层块
let a = 100;
{ // 内层块
console.log(a); // ✅ 正常输出 100
let b = 200;
}
console.log(b); // ❌ ReferenceError:b 不在当前块内
}
这种“向外查找、不向内穿透”的规则,就是块级作用域的查找逻辑,也是它和函数作用域在嵌套行为上一致的地方。
for 循环是个典型且特殊的例子
for (let i = 0; i 中的 <code>let i,不仅让 i 在循环体 {} 内有效,而且每次迭代都会创建一个**新的块级绑定**。所以:
- 循环结束后
console.log(i)报错 - 循环内定义的函数能记住各自轮次的
i值(闭包基础) - 即使在循环体内再写
let i = 'abc',也不会报错——它只是在本轮子块中声明了另一个i
这正是 let + {} 在实际语句中协同工作的体现,不是语法糖,而是运行时实实在在的绑定机制。


















