You need to enable JavaScript to run this app. Mozilla JS getter文档示例如何体现lazy/memoized懒加载缓存特性?
优惠活动
大模型
产品
解决方案
定价
更多

Mozilla JS getter文档示例如何体现lazy/memoized懒加载缓存特性?

核心原理说明

JS 访问器属性的执行逻辑

首先明确 JS 中对象属性的两种类型:

  • 访问器属性:通过get/set语法定义,读取/赋值时会执行对应的函数,本身不存储实际值
  • 数据属性:普通的键值对属性,读取时直接返回存储的静态值

你在对象字面量中定义的get notifier()本质是给对象添加了一个访问器属性,整个 memoization 流程如下:

  1. 首次读取obj.notifier时,JS 匹配到该访问器属性,触发对应的 getter 函数执行
  2. delete this.notifier执行:此时删除的是这个原本存在的访问器属性,执行完成后对象上已经没有notifier相关的任何属性
  3. return this.notifier = 计算结果执行:由于对象上已经不存在notifier属性,JS 会自动给对象新增一个数据属性,存储计算结果,之后直接返回该值
  4. 后续再读取obj.notifier时,JS 会直接匹配到这个新增的数据属性,直接返回存储的值,不会再触发原来的 getter 函数,自然也不会再执行delete和计算逻辑,实现了只计算一次的缓存效果。

你可以通过Object.getOwnPropertyDescriptor(obj, 'notifier')分别打印首次读取notifier前后的属性描述符,就能直观看到属性从访问器属性变成数据属性的变化。

认知误区解释

你直觉认为delete会清空缓存,是搞反了执行顺序:delete只在第一次触发 getter的时候执行,删除的是旧的访问器属性,后续 getter 根本不会被调用,delete自然也不会再执行,不存在每次清空缓存的情况。

不带delete时重复计算的原因

如果删掉delete语句:

  • 你在 getter 中执行this.notifier = 计算结果时,对象上的notifier访问器属性仍然存在
  • 给访问器属性赋值时,如果没有定义对应的set方法,赋值操作会直接被忽略,对象上永远不会生成存储值的数据属性
  • 所以每次读取obj.notifier都会触发 getter 执行,导致计算逻辑重复运行。

和 Ruby memoization 逻辑的对比

Ruby 的@property ||= calc()是通过额外的实例变量存储缓存值,属于额外加了一层缓存判断;而 JS 的这个实现是直接把「需要执行计算的访问器属性」替换成「直接返回值的数据属性」,两种实现逻辑不同,但最终效果一致,都是只在首次读取时执行计算,后续直接返回缓存结果。

内容的提问来源于stack exchange,提问作者Zhao Li

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.14 07:45:05