如何实现可多次调用的defaultMethod?参数默认值继承问题
解决defaultMethod函数多次调用失效问题
需求说明
实现defaultMethod函数,接收一个目标函数与默认参数字典,返回带有默认参数的新函数,核心要求是支持多次调用更新默认参数:
- 基础示例:
function add(a,b) { return a+b;}; var add_ = defaultMethod(add,{b:9}); console.log(add_(10)); // 预期返回19(10+9) - 多次调用示例:
var add_ = defaultMethod(add,{b:9}); // 初始设置b默认值9 add_ = defaultMethod(add_,{b:3, a:2}); // 更新b为3、添加a默认值2 let res = add_(10); // 传入a=10 console.log(res); // 预期返回13(10+3)
现有实现的问题
现有代码单次调用正常,但多次调用时,console.log(requiredArgs)输出['...args']而非原函数的['a','b'],导致逻辑失效。原因是:第一次调用defaultMethod返回的是匿名包装函数,第二次传入该包装函数时,func.toString()解析的是包装函数的参数(...args),而非原始目标函数的参数列表。
解决方案
核心思路是让每个包装函数保留原始目标函数的引用,同时累计每次传入的默认参数,确保多次调用时始终能获取到正确的参数列表和最新的默认值。修改后的代码如下:
function defaultMethod(func, params) { // 追溯到最原始的目标函数,避免解析包装函数的参数 const originalFunc = func.__originalFunc__ || func; const funcStr = originalFunc.toString(); const requiredArgs = funcStr .slice(funcStr.indexOf('(') + 1, funcStr.indexOf(')')) .match(/([^\s,]+)/g) || []; // 创建新的包装函数 const wrappedFunc = function (...args) { const calledArgs = [...args]; // 复制参数数组,避免修改原数组 // 合并历史默认参数与新传入的参数,新参数覆盖旧值 const mergedDefaults = {...func.__defaultParams__, ...params}; // 填充缺失的参数 for (let i = 0; i < requiredArgs.length; i++) { if (calledArgs[i] === undefined) { calledArgs[i] = mergedDefaults[requiredArgs[i]]; } } return originalFunc(...calledArgs); }; // 给包装函数添加属性,存储原始函数和累计的默认参数 wrappedFunc.__originalFunc__ = originalFunc; wrappedFunc.__defaultParams__ = {...func.__defaultParams__, ...params}; return wrappedFunc; }
关键修改点
- 保留原始函数引用:通过自定义属性
__originalFunc__,每次调用都能获取到最开始的目标函数,确保参数解析始终正确 - 累计默认参数:用
__defaultParams__存储每次传入的默认参数,新参数会覆盖旧的同名参数,实现默认值的更新 - 参数数组隔离:复制
args数组避免修改原输入,保证函数的纯净性
测试验证
运行多次调用的示例代码,输出结果为13,符合预期。
内容的提问来源于stack exchange,提问作者Bipe
相关产品推荐
相关产品推荐

