javascript只采用词法作用域,变量查找由函数定义位置决定,与调用方式无关;动态作用域在js中不存在,仅能通过不推荐的eval()或with模拟。

JavaScript 中没有真正的动态作用域,它只采用词法作用域(也叫静态作用域)。所谓“本质区别”,其实是两种不同设计哲学的变量查找机制,关键不在“JS 支持哪种”,而在“JS 坚决不用哪一种”。
词法作用域:由代码位置决定查找路径
变量在哪一层函数或块中定义,就决定了它能被谁访问。查找时,引擎沿着函数定义时嵌套的层级向上找,和函数怎么被调用完全无关。
- 定义即锁定:函数内部引用的变量,取决于它写在哪儿,而不是谁调了它
- 查找链固定:比如 inner 函数里用 x,引擎先查 inner 自己的作用域,再查 outer(定义时外层),最后到全局——这条链在写完代码那一刻就定死了
- 支持遮蔽:内层同名变量会覆盖外层,但外层变量依然存在,只是暂时不可见
动态作用域:由调用顺序决定查找路径
变量查找不看函数写在哪,而看它被谁调用、当前执行栈顶层是谁。这种机制在 JavaScript 中不存在原生实现,仅能靠 eval() 或 with 模拟(强烈不推荐)。
- 调用时才确定:函数 A 调用函数 B,B 访问一个未声明的变量,就会去 A 的作用域里找,而不是 B 定义处的外层
- 行为不稳定:同一段函数代码,在不同调用链下可能读取完全不同的变量
- JS 明确拒绝:this 的绑定虽是动态的,但变量查找永远不走这条路——这是语言设计的硬性边界
一个对比例子看清区别
这段代码在 JS 中输出 10:
DMap GL地图JSAPI(dmapgl)开发指南。用于编写、审查、调试 DMap 地图 API 代码,涵盖地图初始化、覆盖物渲染、图层管理、事件处理、控件交互等任务。当用户提及 dmap、dmapgl、jsapi‑gl 或相关地图开发需求时自动触发。
var value = 10;
function foo() { console.log(value); }
function bar() { var value = 20; foo(); }
bar(); // 输出 10(词法:foo 定义在全局,查全局 value)
如果 JS 是动态作用域,foo 就会输出 20(因为它是被 bar 调用的,bar 里有 value=20)——但它没这么做,这就是根本分水岭。
为什么容易混淆?
开发者常把 this 的动态绑定 和 变量的词法查找 搞混。例如:
- obj.method() 中 this 指向 obj —— 这是动态的
- method 内部访问变量 x —— 这仍是词法的,和谁调用 method 无关
记住:JS 的 this 可以变,但作用域链从不随调用改变。










