外观
作用域、闭包与 this
- 状态:未准备
- 适用方向:前端 / Go 全栈
- 最近复习:待填写
- 下次复习:待安排
一句话回答
作用域决定变量查找位置,闭包让函数继续访问创建时的词法环境;普通函数的 this 主要看调用方式,箭头函数的 this 从外层词法环境继承。
原理解释
var、let、const
var 主要是函数作用域,声明提升并初始化为 undefined;let/const 是块级作用域,声明前访问处于暂时性死区,会抛 ReferenceError。const 声明时必须初始化。不能简单说 let/const“完全没有提升”。
闭包捕获的是绑定
js
function counter() {
let n = 0
return () => ++n
}
const next = counter()
console.log(next(), next()) // 1 2闭包不是复制一份永远不变的值,而是保留访问词法绑定的能力。var 循环共用绑定,let 循环可建立逐轮绑定。React 每次函数渲染创建新的局部绑定,所以不同渲染的闭包可能看到不同状态快照。
this 的判断方式
obj.fn():普通函数调用时 this 为接收者 obj;把 fn 单独取出再调用会丢失接收者。call / apply显式指定普通函数的 this;bind 创建绑定函数。- 独立普通函数在严格模式下 this 为 undefined;非严格模式的规则不同。
- 箭头函数没有自己的 this,call/apply/bind 不能替换它捕获的 this,也不能用 new 构造。
- new 调用有构造规则;不要把所有特殊场景压成一句“谁调用就指向谁”。
场景与边界
闭包适合封装私有状态、工厂、事件回调。闭包本身不是内存泄漏;长生命周期监听器或计时器持续保留不再需要的数据,才是常见问题,应及时解绑或清理。
项目中的应用
沿 Blog 滚动监听 和 SimulSpeak 生命周期 检查回调捕获的状态以及取消订阅时保存的函数引用。
常见追问
- call、apply、bind 区别? 前两者立即调用,参数分别逐项和类数组传入;bind 返回新函数,可预置部分参数。
- 为什么移除监听器失败? 重新写的匿名函数是不同引用,且捕获选项需匹配。
- 模块顶层 this 是什么? ES module 顶层为 undefined,不能照搬传统浏览器脚本顶层结论。