JavaScript词法作用域由函数定义位置静态决定,与调用位置无关;作用域链在解析时构建,从函数自身逐级向外指向外层词法环境直至全局;遮蔽关系和变量查找均按源码嵌套结构确定。

JavaScript 的词法作用域,核心就一条:**函数能访问哪些变量,取决于它在源代码里写在哪,而不是它后来被谁、在哪调用的。**
函数定义位置决定作用域链起点
引擎在解析代码时(词法分析阶段),就根据大括号嵌套和函数声明的位置,静态构建出一个“作用域链”结构。这个链从函数自身开始,逐级向外指向其外层词法环境,最终到全局。
- 比如一个函数写在全局下,它的外层就是全局作用域;
- 如果它写在另一个函数内部,那它的外层就是那个父函数的作用域;
- 这个关系在代码一加载就固定了,运行时无论怎么调用、传给谁、嵌套多深,都不会改变。
调用位置完全不影响变量查找路径
即使把一个函数作为参数传到很远的地方再执行,它依然按定义时的嵌套结构去查变量。
- 例如:function foo() { const x = 10; return function bar() { console.log(x); }; } const fn = foo(); setTimeout(fn, 100); —— bar 是在 foo 内部定义的,所以它始终能访问 x,哪怕在 setTimeout 的异步回调中执行;
- 反过来,如果把 bar 声明在全局,那它就只能访问全局变量,哪怕是在 foo 里调用它,也拿不到 foo 内部的 x。
遮蔽(Shadowing)也是静态确定的
同名变量的覆盖关系,在代码写完那一刻就定死了。
- 内层函数用 let 声明了和外层同名的变量,那内层的引用一定指向自己声明的那个;
- 这种遮蔽不看执行顺序,也不看调用栈深度,只看代码块的嵌套层级和声明语句的书写位置。
和 this 的关键区别在这里
this 是运行时绑定的,取决于函数怎么被调用(谁点的、有没有 new、是否箭头函数);而词法作用域是写完就锁死的,和调用方式毫无关系。一个函数可以每次 this 不同,但它能读到的变量永远只认它出生的地方。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











