
本文解析 javascript 中 `i++` 与 `++i`(以及 `i--` 与 `--i`)的本质差异,说明为何在事件处理中误用后置递增/递减会导致“首次点击无效”等反直觉行为,并提供正确写法与健壮实践。
问题的核心在于对后置递增/递减运算符(i++ / i--)执行时机的理解偏差。
在你的原始代码中:
tracker.innerHTML = i++;
这行语句的执行顺序是:
- 先将 i 的当前值赋给 tracker.innerHTML;
- 再将 i 自增 1。
也就是说,i++ 返回的是自增前的旧值。因此,第一次点击时:
立即学习“Java免费学习笔记(深入)”;
- i 初始为 0;
- tracker.innerHTML = i++ 实际执行的是 tracker.innerHTML = 0,然后 i 才变成 1;
- 页面显示仍为 0,但内部状态 i 已更新为 1;
- 第二次点击时,i 是 1,赋值 tracker.innerHTML = 1,之后 i 变为 2 —— 此时才看到数字变化。
这就解释了“需两次点击才显示变化”的现象。同理,i-- 也返回旧值,导致递减逻辑同样滞后一帧。
✅ 正确做法是使用前置递增/递减运算符(++i / --i):它先修改变量值,再返回新值。
同时,为避免食物数量变为负数,undonate 还应添加边界校验:
const donateButton = document.getElementById("donate");
const unDonateButton = document.getElementById("undonate");
const tracker = document.getElementById("container");
let i = 0; // 推荐使用 let 替代 var(块级作用域更安全)
tracker.textContent = i; // 使用 textContent 更安全(防 XSS),且语义更清晰
const donate = () => {
donateButton.style.backgroundColor = 'red';
tracker.textContent = ++i; // 先 +1,再赋值显示
};
const undonate = () => {
if (i > 0) {
unDonateButton.style.backgroundColor = 'blue';
tracker.textContent = --i; // 先 -1,再赋值显示
} else {
// 可选:视觉反馈提示已达下限
unDonateButton.style.backgroundColor = '#ccc';
setTimeout(() => {
unDonateButton.style.backgroundColor = '';
}, 300);
}
};
donateButton.addEventListener("click", donate);
unDonateButton.addEventListener("click", undonate);? 关键总结:
- i++ → 返回旧值,再自增(post-increment);
- ++i → 先自增,再返回新值(pre-increment);
- UI 更新需反映最新状态,故应优先选用 ++i / --i;
- 始终对用户操作做边界防护(如禁止负数),提升程序鲁棒性;
- 使用 textContent 替代 innerHTML(除非需渲染 HTML),既安全又高效。
掌握这一细微却关键的语法差异,能帮你避开大量看似“玄学”的状态同步 bug。










