如何用闭包与装饰器实现仅可调用一次的JavaScript函数?
实现仅能调用一次的函数(闭包+装饰器方式)
问题描述
我希望用闭包和装饰器实现一个仅能调用一次的函数,原以为理解相关原理,但实际编写时遇到了问题:
初始代码
export function once(callback) { return (...args) => { function once(fun){ let called = false; return () => { if(!called){ const result = fun(...arguments); called = true; return result; } } } // 必须仅调用一次`callback`! // 必须缓存其返回值。 return callback(...args); // 多次调用时无效果 }; }
我尝试将最后一行修改为:
... return once(callback(...args)); }; }
这不应该能实现函数仅调用一次的效果吗?
问题分析与正确实现
你的代码存在两个核心问题:
- 内部嵌套的
once函数未生效:外层once返回的箭头函数每次被调用时,都会重新定义内部的once,最后直接执行callback(...args),等于每次调用都会触发原回调,完全没用到闭包的状态控制逻辑。 - 修改后的代码逻辑错误:
once(callback(...args))是先执行了callback并把结果传给内部once,而不是传入回调函数本身。这会导致原回调在传入时就已经执行,后续返回的函数根本无法控制调用次数。
正确实现
核心思路是用外层函数的作用域保存called状态和回调结果,让返回的闭包函数共享这个状态:
export function once(callback) { let called = false; let result; return (...args) => { if (!called) { result = callback(...args); called = true; } return result; }; }
逻辑说明
called和result定义在外层once函数中,每次调用once(callback)都会创建独立的状态变量,不同的“单次调用函数”之间不会互相影响。- 返回的箭头函数每次被调用时,先检查
called:未调用则执行原回调、缓存结果并标记已调用;已调用则直接返回缓存的结果。 - 最终实现原回调仅执行一次,后续调用均返回第一次的结果。
测试示例
const logMessage = () => { console.log('这只打印一次'); return '第一次的返回值'; }; const logOnce = once(logMessage); logOnce(); // 打印"这只打印一次",返回"第一次的返回值" logOnce(); // 无打印,返回"第一次的返回值" logOnce(); // 同上,无打印,返回缓存值
内容的提问来源于stack exchange,提问作者MyNameIsArjen
相关产品推荐
相关产品推荐

