静态作用域指变量查找依赖函数定义时的嵌套位置而非调用位置,作用域链在代码编写时即确定,闭包是其自然结果;动态作用域则依据调用栈查找变量。

静态作用域(也叫词法作用域)的识别,关键看变量查找是否依赖函数定义时的代码位置,而不是调用时的位置。只要满足“写代码时就定死了变量在哪一层能被访问”,那就是静态作用域。
看函数定义的位置,而不是调用的位置
函数内部访问一个变量,JavaScript 和 Python 等语言会沿着函数**定义时所处的嵌套结构**向上找,而不是顺着谁调用了它来查。
- 比如一个函数在全局里定义,哪怕后来被传进另一个函数、再从深层对象里调用,它仍然只认自己写在哪儿——也就是只往全局作用域找自由变量
- 嵌套函数中,内层函数定义在哪个外层函数里,它的上一级作用域就是那个外层函数,不是调用它的函数
变量查找路径由嵌套层级决定
每次访问变量,引擎按固定顺序搜索:当前作用域 → 定义时的外层作用域 → 再外层 → 全局作用域。这个链条叫“作用域链”,是静态写死的。
- 查找从不跳转到“调用者的作用域”——哪怕调用者刚好有同名变量,也不会被用到
- 如果某层作用域用了 let/const 声明,那它只对本块及其中嵌套生效;var 会提升到函数级,影响整个函数作用域
- ES6 后支持块级作用域,但仍是静态的:
{ let x = 1; }里的x只在花括号内可见,且这个范围在写完就确定了
闭包是静态作用域的自然结果
当函数返回后仍能访问其定义时的外层变量,说明作用域链被保留下来了——这就是闭包。它不是特殊机制,而是静态作用域在运行时的体现。
- 函数携带了它定义时的“词法环境”,不管在哪里执行,都沿用这条链找变量
- 多个闭包共享同一外层作用域时,修改其中一个闭包里的变量,其他闭包也能读到新值
对比动态作用域快速验证
如果你把函数挪个地方定义,变量行为变了,那可能是动态作用域;但如果只是换个地方调用,行为完全不变,那就是静态作用域。
- 例如:函数 A 定义在全局,里面访问
name;它被 B 函数调用,而 B 自己声明了name = 'Bob'——静态作用域下,A 仍去全局找name,不会用 B 的 - 动态作用域语言(如某些 Lisp 方言)才会让 A 拿到 B 的
name

















