词法作用域确保高阶函数访问定义时的变量,靠“定义位置决定作用域”;JavaScript在函数定义时构建作用域链,执行时按链向上查找;闭包使外层变量持续存活;箭头函数继承外层词法作用域与this;捕获的是变量绑定而非值拷贝。

词法作用域确保高阶函数能正确访问定义时的变量,靠的是“定义位置决定作用域”,而不是“调用位置”。只要高阶函数(比如 map、filter 传入的回调)是在某个作用域内定义的,它就永久绑定那个环境里的变量,哪怕之后在别处执行也不会变。
变量查找走的是定义时的作用域链
JavaScript 引擎在函数**定义时**就确定了它的外层作用域,并构建好作用域链。执行时只是按这条链一层层向上找变量:
- 先查自己函数内部有没有声明同名变量
- 没有就查定义它时所在函数的作用域(不是调用它时的函数)
- 再往上直到全局作用域
例如:
let base = 100;function makeMultiplier() {
let factor = 2;
return function(x) { return x * factor + base; }; // 这里定义,绑定了当前的 factor 和 base
}
const mul = makeMultiplier();
let base = 999; // 修改全局 base
console.log(mul(5)); // 输出 200,不是 1009 —— 因为用的是定义时捕获的 base=100
闭包让外部变量“活下来”
高阶函数的回调常作为返回值或事件处理器被保留下来,此时外层函数早已执行完毕。但因为回调形成了闭包,JS 的垃圾回收器不会释放它所依赖的外层变量:
立即学习“Java免费学习笔记(深入)”;
- 外层函数执行完,其执行上下文本该销毁
- 但若内部函数被引用(如赋给变量、传给
setTimeout、塞进数组),引擎会保留其词法环境 - 于是
factor、base等变量持续可访问
箭头函数天然适配词法作用域
箭头函数不创建自己的 this、arguments,也不改变作用域链——它完全沿用外层函数的词法作用域:
- 在类方法中用
arr.map(x => x * this.value),this指向类实例,因为箭头函数从定义位置继承了this - 普通函数写法需
const self = this或.bind(this),本质是手动模拟词法捕获 - 箭头函数省去这些,是因为它从定义起就“认准”外层那一圈变量和
this
注意:变量值不是快照,而是实时引用
词法作用域捕获的是变量的**绑定关系**,不是值的拷贝。如果外层变量后续被重新赋值,回调里读到的就是新值:
let count = 0;const fn = () => count;
console.log(fn()); // 0
count = 100;
console.log(fn()); // 100
这点在异步或循环中容易出错,比如用 for (var i...) 配 setTimeout,所有回调共享同一个 i 绑定。


















