复现lodash _.once函数需至少2次调用才生效的问题排查与求解
_.once 函数复现问题修复 问题根因
你当前的实现错误嵌套了两层返回函数,把「存储参数」的逻辑和「执行目标函数」的逻辑拆到了不同的函数调用层级,没有在闭包内维护执行状态标记,导致需要3次调用才能触发目标函数执行,完全不符合once的调用链路。
现有错误实现
function onceCopy (testFunc) { const copyFunc = (a) => { const copyFunc2 = (b) => { return testFunc(a); }; return copyFunc2; }; return copyFunc; };
这段代码的执行链路问题:
- 调用
onceCopy(testFunc)仅返回第一层函数copyFunc,没有初始化执行状态、结果缓存 - 第一次调用
copyFunc(a)时不会执行目标函数,只会返回新的嵌套函数copyFunc2 - 直到第三次调用(拿到
copyFunc2后传参调用)才会执行testFunc,且仅能拿到第二次调用传入的参数a
标准_.once的预期逻辑
- 接收目标函数后,在闭包内维护两个私有状态:函数是否已执行的标记、第一次执行的返回结果缓存
- 第一次调用返回的包装函数时,透传参数、绑定正确的this指向执行目标函数,缓存结果、标记为已执行
- 后续所有对包装函数的调用,直接返回缓存的结果,目标函数全程仅执行1次
正确实现代码
function onceCopy(testFunc) { let called = false; let cachedResult; return function(...args) { if (!called) { cachedResult = testFunc.apply(this, args); called = true; } return cachedResult; }; }
效果验证
用给出的测试场景验证:
function multiplyBy3 (a) { console.log('目标函数执行'); return a * 3; } const actualFunction = onceCopy(multiplyBy3); console.log(actualFunction(1)); // 输出:目标函数执行、3 console.log(actualFunction(66)); // 输出:3,不会再次触发目标函数执行 console.log(actualFunction(100, '无关参数')); // 输出:3,目标函数全程仅执行1次
实现中使用
apply绑定this、透传剩余参数,是为了和lodash官方_.once行为对齐,避免包装函数丢失上下文、漏传参数的边界问题。
内容的提问来源于stack exchange,提问作者Yassmine
相关产品推荐
相关产品推荐

