标准答案
- once 需要在闭包里保存是否已经执行过。
- 第一次调用时执行原函数,并保存返回值。
- 后续调用直接返回第一次的结果。
- 调用原函数时要保留 this 和参数。
- 如果原函数可能抛错,要明确失败是否也算已经执行过。
题目解析
once 常用于初始化、事件绑定、埋点上报、弹窗展示等只允许发生一次的操作。它控制的是执行次数,不是防抖或节流。
保留 this 和参数很重要。被包装的函数可能是对象方法,也可能依赖第一次调用传入的参数。
异常策略要说清楚。很多实现会在函数成功返回后才标记为已执行;也有实现会把抛错也视为一次执行,这取决于业务语义。
代码示例
下面的版本在原函数成功返回后缓存结果。
JavaScript
function once(fn) {
let called = false
let result
return function onceWrapper(...args) {
if (called) {
return result
}
result = fn.apply(this, args)
called = true
return result
}
}常见误区
- 只用全局变量记录状态,导致多个 once 包装函数互相影响。
- 执行原函数时没有保留 this 和参数。
- 没有明确原函数抛错时是否允许下一次重试。