作用域链在函数定义时静态确定,由[[environment]]属性指向其词法外层环境,形成从内到外、不可变的单向链;变量查找仅沿此链向上遍历,与调用时机和位置无关。

函数创建时,outer 指针就已确定——它不看函数怎么被调用,只认函数在代码里“出生的位置”。这个过程完全发生在解析(编译)阶段,和运行时无关。
函数定义时,引擎立即记录“老家”环境
当 JavaScript 引擎扫描到一个函数声明(比如 function inner() { }),它会立刻根据该函数在源码中的嵌套位置,找到其直接外层的词法环境,并把这个环境对象的引用存进函数内部的 [[Environment]] 属性中。
- 如果
inner写在function outer() { }的函数体里,[[Environment]]就指向outer创建时的词法环境 - 如果
inner写在全局作用域下,[[Environment]]就直接指向全局词法环境 - 这个绑定动作在函数对象生成那一刻就完成,不是等调用才去查
outer 链是静态嵌套结构,不是动态拼接
outer 不是运行时算出来的,而是函数定义时就“刻进基因”的一条单向链。每个词法环境都自带一个 outer 字段,它指向自己上一级的词法环境,顶层为 null。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
globalEnv.outer === nullouterEnv.outer === globalEnvinnerEnv.outer === outerEnv- 整条链从内到外,就是函数定义时所处的嵌套层级的镜像
变量查找只是按图索骥,不重新判断
执行函数时遇到自由变量,引擎不会问“我现在在哪个上下文里”,而是直接从当前函数的 [[Environment]] 开始,顺着 outer 一级级往上翻,直到找到或报错。
- 哪怕
inner被返回、赋值给全局变量、传给setTimeout,它的[[Environment]]仍指向当初写它时的outerEnv - 即使
outer执行结束、上下文本该销毁,只要inner还活着,引擎就会保留outerEnv(形成闭包),但这是被动结果,不是运行时主动选择 - 不存在“调用时重连 outer”的机制;链一旦建好,全程不变
为什么不能靠运行时推断?因为要守住词法作用域
JS 明确拒绝动态决定作用域,就是为了保证可预测性和可分析性。像 eval 和 with 被限制,正是因为它们会破坏这种静态关系——让变量可见性依赖执行路径,而不是代码位置。
- IDE 补全、ESLint 提示、类型检查工具,全靠这个静态链提前知道变量来源
- 同名变量谁生效、遮蔽关系如何,都在你敲下代码那一刻定死
- 哪怕函数延迟执行、跨模块导入、甚至通过字符串拼接构造,都不影响它认“老家”
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










