JavaScript采用词法作用域,变量查找只取决于函数定义位置而非调用位置;作用域链在代码解析时静态确定,包含自身、外层函数至全局;闭包正是该静态特性的直接体现。

函数在哪里被调用,对变量查找没有影响——这是 JavaScript 词法作用域最核心的静态特性。变量能不能访问、访问到谁,只取决于函数写在代码里的位置,而不是它后来被谁调用、在哪执行。
定义位置决定作用域链
函数一写出来,它的作用域链就固定了:从自身开始,逐级向上包含外层函数、再外层函数,直到全局。这个链条在代码解析阶段就确定,运行时不会因调用位置改变。
- 一个在全局写的函数,内部查变量永远只看全局和自己,哪怕被传进十层嵌套的回调里调用,也还是走这条老路
- 一个在 function A 内部定义的函数,天然拥有访问 A 中 let/const/var 的权利——不是因为 A 正在运行,而是因为它“出生”在 A 里面
- 块级作用域(let/const)也会被纳入这条链;var 虽不创建块作用域,但仍在函数或全局作用域中参与查找
调用位置不影响变量查找结果
下面这段代码能清楚说明问题:
let value = 1;
function foo() { console.log(value); }
function bar() {
let value = 2;
foo(); // 在 bar 里调用 foo
}
bar(); // 输出 1,不是 2
foo 定义在全局,所以它查 value 只去全局找。bar 里虽然有同名变量,但 foo 根本不“认”bar 的作用域——它没写在 bar 里面,就不在它的作用域链上。
和 this 的动态性形成鲜明对比
同一个函数,调用方式不同,this 可能指向 window、对象、undefined 或其他值——这是动态绑定。
- 但函数内访问普通变量(比如 value、count)始终走静态作用域链,不受 this 影响
- this.xxx 查的是对象属性,走原型链;而 xxx 查的是变量,走词法作用域链——两者机制完全不同
- 混淆这两者,是很多作用域问题的根源
闭包就是静态作用域的自然体现
当一个函数返回了内部函数,而该内部函数引用了外层变量,这些变量不会被释放——不是靠“记住调用栈”,而是因为引擎在定义时就把外层词法环境锁进了函数的 [[Environment]] 属性中。
- outer 执行完、上下文销毁了,inner 仍能访问 outer 的变量,靠的就是定义时捕获的静态环境
- 如果 JS 是动态作用域,inner 就会按调用位置去找变量,闭包就无法存在
- 闭包不是语法糖,是词法作用域这一静态特性的直接产物
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











