跳到正文

作用域、闭包与 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,不能照搬传统浏览器脚本顶层结论。

参考资料 ​

理解机制,讲清取舍,用复盘检验掌握。