JavaScript 点击逐次遍历对象数组的越界报错与边界控制异常问题
越界报错与迭代提前停止的根因
- 抛出
app.js:70 Uncaught TypeError: Cannot read property 'question' of undefined的核心原因:索引自增与边界判断的执行顺序完全颠倒,通常是先把索引自增到questions.length(数组有效最大索引为questions.length - 1,这个值本身就是越界的),再执行边界判断,等判断逻辑运行时,代码已经在读取越界位置的元素属性了,自然触发报错。 - 拦截逻辑导致迭代提前停止的原因:边界拦截的触发时机完全错位,新增的
if ((i + 1) == (questions.length)){i--;}判断,会在索引走到倒数第二题时就触发回退,直接跳过最后一题的渲染节点。
修复方案
所有交互逻辑严格遵循「先做边界校验,再操作数组,最后更新索引」的顺序,数组有效索引范围固定为0 <= 有效索引 < questions.length。
典型错误逻辑还原
以下写法是触发两个bug的共性问题:
let i = 0; nextBtn.onclick = () => { // 错误1:先自增索引,等索引越界了才做判断 i++; // 这行执行时如果i等于questions.length,questions[i]就是undefined,直接抛属性读取错误 questionText.textContent = questions[i].question; // 错误2:等读取完元素属性才判断越界,完全起不到拦截作用 if (i == questions.length) { i = 0; } // 错误3:拦截逻辑放在自增之前,触发条件错位 if ((i + 1) == (questions.length)){i--;} }
正确实现参考
非循环遍历版本(最后一题后按钮禁用)
如果业务逻辑要求遍历到最后一题后停止,不需要循环回到开头,按以下逻辑实现即可:
let i = 0; // 页面初始化渲染第一题 renderQuestion(questions[i]); nextBtn.onclick = () => { // 第一步:先判断是否已经到达最后一题的位置 if (i >= questions.length - 1) { // 到达最后一题,禁用按钮,不再执行后续逻辑 nextBtn.disabled = true; return; } // 边界校验通过后,安全自增索引 i++; // 此时i的最大值为questions.length -1,绝对不会出现越界 renderQuestion(questions[i]); }
循环遍历版本(最后一题后点击回到第一题)
如果需要无限循环遍历题目,直接用取模运算处理边界,不需要写多余的if判断:
let i = 0; renderQuestion(questions[i]); nextBtn.onclick = () => { // 自增后用数组总长度取模,自动处理越界回退逻辑 i = (i + 1) % questions.length; renderQuestion(questions[i]); }
避坑提醒
- 牢记JavaScript数组的半开边界特性:数组最后一个元素的索引永远是
length - 1,访问questions[questions.length]必然返回undefined。 - 所有可能引发索引越界的判断,必须放在访问数组元素的代码之前,写在访问之后的判断完全没有拦截作用。
内容的提问来源于stack exchange,提问作者Sole
相关产品推荐
相关产品推荐

