作用域是JavaScript引擎执行时严格按规则查找变量的路径机制。全局作用域指不在任何函数或块内的顶层环境;局部作用域分函数作用域(var/function受其约束)和块级作用域(let/const在{}中触发);作用域链是向上逐层查表,同名变量会被遮蔽;作用域在定义时即确定,与调用无关。

作用域不是“变量在哪能用”的模糊概念,而是 JavaScript 引擎在执行时**严格按规则查找变量的路径机制**。理解它,关键不在背定义,而在看代码运行时“它到底找谁”。
全局作用域:不是“整个文件”,而是“没被函数或块包住”的顶层
全局作用域 ≠ 整个 .js 文件内容,而是指:不在任何函数、也不在任何 {} 块(如 if、for)内声明的变量/函数所处的环境。
-
var a = 1写在最外层 →a是全局变量,挂到window.a(浏览器中) -
let b = 2写在最外层 →b是全局变量,但不挂到window,这是 ES6 的设计差异 -
function foo(){}写在最外层 →foo是全局函数,可 anywhere 调用 -
if (true) { var c = 3; }→c仍属于全局作用域(var没有块级作用域) -
if (true) { let d = 4; }→d只在该{}内有效,外部console.log(d)报ReferenceError
局部作用域:函数是“老式隔离单位”,{} 是“ES6 新隔离单位”
局部作用域分两类,但行为完全不同:
-
函数作用域:由
function创建,var、function声明全受其约束;let/const也在此内有效,但还受更细粒度的块限制 -
块级作用域:仅由
let和const在{}中触发(if、for、纯{}都算),var完全无视它 - 嵌套函数会形成作用域链:内部函数能访问外部函数的变量,但反过来不行
- 常见错误:
for (var i = 0; i console.log(i), 0); }→ 全部输出3,因为var i是函数作用域,循环结束时i === 3;改用let i就输出0, 1, 2
作用域链:不是“继承”,是“向上逐层查表”
当执行 console.log(x) 时,JS 引擎不做推理,只做一件事:从当前作用域开始,一层层往上翻变量对象(VO/AO),直到找到 x 或抵达全局也没找到就报错。
- 查找顺序固定:
当前作用域 → 外层函数作用域 → … → 全局作用域,不跳、不跨、不缓存 - 同名变量会被遮蔽:
var x = 10; function f(){ var x = 20; console.log(x); }→ 输出20,不是10 - 闭包本质就是:内部函数记住了自己创建时的外部作用域链,哪怕外部函数已执行完毕
- 性能提示:深层嵌套作用域链不会拖慢运行,但过度依赖链式查找会让代码意图难读,建议用明确命名和小函数拆分
eval 或 with 会动态改变作用域链,但它们已被弃用——现代 JS 的作用域是静态可分析的。











