如何控制函数传递的变量?定时器传参变量无法更新求助
看起来你碰到了定时器闭包导致变量无法更新的经典问题——我之前做类似游戏挂机系统时也踩过一模一样的坑!
问题根源分析
你提到能传递变量但无法更新,核心原因是:当你给定时器回调绑定stats这类变量时,回调函数会捕获变量在创建定时器那一刻的引用快照。如果后续stats的属性被修改(比如stats.actions--),只要stats还是同一个对象,其实是能生效的;但如果stats被重新赋值成了新对象,或者你是通过绑定参数的方式把旧值锁死在回调里,那定时器触发时就只会拿到最初的旧值。
看你给出的tradeSkill函数,它本身是在修改stats的属性,问题大概率出在定时器绑定变量的方式上。
具体解决方案
1. 不要绑定死参数,让回调实时取最新变量
如果之前你是这样写定时器的(把stats作为固定参数绑定):
// 错误示例:这里的stats是创建定时器时的快照,后续更新不会同步 const timer = setInterval(tradeSkill.bind(null, msg, what, type, amount, userData, stats), 2000);
改成直接在回调函数里传入当前最新的stats:
// 正确做法:每次定时器触发时,都传入当前最新的stats对象 const timer = setInterval(() => { tradeSkill(msg, what, type, amount, userData, stats); }, 2000);
这样每次触发回调,都会拿到stats的最新引用,修改stats.actions这类属性自然会同步生效。
2. 若stats会被重新赋值,用容器对象保留引用
如果你的业务逻辑中需要把stats整个替换成新对象(比如stats = {...stats, actions: 10}),那可以用一个容器对象包裹stats,保证引用始终不变:
// 用容器包裹stats,后续只更新容器内部的current属性 const statsContainer = { current: stats }; // 定时器回调里取容器的current值 const timer = setInterval(() => { tradeSkill(msg, what, type, amount, userData, statsContainer.current); }, 2000); // 后续更新stats时,直接替换current statsContainer.current = newUpdatedStatsObject;
3. 给你的tradeSkill函数补全定时器清除逻辑
另外看你函数里的逻辑:当stats.actions <=0时发送报告,这里一定要记得清除定时器,避免后续继续无效触发:
tradeSkill: (msg, what, type, amount, userData, stats, timerId) => { stats.actions--; if (stats.actions <= 0) { // 必须清除定时器,防止重复执行 clearInterval(timerId); // 发送报告私信 userData.send({ embed: { color: 3447003, title: `Farming Report For ${type}`, fields: [ { name: 'Stats', value: `Gathered: ${stats.yield}\nEXP Gained: ${stats.exp}` } ] } }); } } // 创建定时器时把timerId传入回调 const timerId = setInterval(() => { tradeSkill(msg, what, type, amount, userData, stats, timerId); }, 2000);
核心总结
本质上就是避免让定时器回调捕获变量的“静态快照”,而是让它每次触发时都能拿到变量的最新动态引用。只要调整定时器的调用方式,这个问题就能解决。
内容的提问来源于stack exchange,提问作者William
相关产品推荐
相关产品推荐

