JavaScript for循环中splice删除数组指定元素失效问题
问题原因
- 核心错误是
splice方法调用参数完全不符合语法要求:Array.splice()的第一个参数是数值类型的删除起始索引,第二个参数是数值类型的删除元素个数。你代码里写的department_arr.splice(course, course)传入了两个对象作为参数,JS会将对象隐式转换为数字,最终得到NaN,传入非法索引时splice不会执行任何有效删除,匹配成功的课程项始终留在department_arr数组中。 - 遍历逻辑没有做命中拦截:for...of循环每次执行时,不管内层if有没有命中匹配,都会走到循环最后一行追加空字段表格行的逻辑,匹配成功的课程自然会同时渲染出带作业数据的行和空字段行。
- 额外风险:如果后续修正splice参数后,在for...of正向遍历数组的过程中直接splice修改原数组,会导致数组长度变化、元素索引前移,很容易出现漏遍历、重复遍历的问题。
- 另外你代码中所有表格行都设置了相同的
id="accordion",HTML规范要求id在页面中全局唯一,重复id会导致后续DOM操作、事件绑定出现异常。
修复方案
不需要在遍历过程中边遍历边删除数组元素,用匹配标记控制渲染逻辑即可,等全部遍历完成后再统一过滤更新原数组,从根源上避免遍历错乱问题,参考代码如下:
for (let course of department_arr) { // 标记当前课程是否匹配到新作业 let isMatched = false; for (let i in new_assignment_ls) { if (course.CourseName == new_assignment_ls[i][3] && course.Semester == new_assignment_ls[i][4].split(' ').slice(1).join(' ') && course.Route == new_assignment_ls[i][5].split(' ').slice(1).join(' ')) { dataHtml += `<tr class='accordion' onclick="newAssign(this)"><td>${new_assignment_ls[i][0]}</td><td>${new_assignment_ls[i][1]}</td><td>${new_assignment_ls[i][2]}</td><td>${course.Year}</td><td>${course.Semester}</td><td>${course.Route}</td><td>${course.CourseName}</td></tr>`; isMatched = true; // 匹配到即可终止内层循环,减少不必要的遍历 break; } } // 仅未匹配到新作业的课程,才渲染空字段行 if (!isMatched) { dataHtml += `<tr class='accordion' onclick="newAssign(this)"><td></td><td></td><td></td><td>${course.Year}</td><td>${course.Semester}</td><td>${course.Route}</td><td>${course.CourseName}</td></tr>`; } } // 遍历完成后统一过滤掉已匹配作业的课程,更新原数组 department_arr = department_arr.filter(course => { return !new_assignment_ls.some(assign => { return course.CourseName == assign[3] && course.Semester == assign[4].split(' ').slice(1).join(' ') && course.Route == assign[5].split(' ').slice(1).join(' ') }) })
如果你一定要在遍历过程中用splice删除元素,不要用for...of,改用倒序for循环遍历,删除元素不会影响未遍历部分的索引:
// 倒序遍历,从最后一个元素开始遍历 for (let idx = department_arr.length - 1; idx >= 0; idx--) { const course = department_arr[idx]; let isMatched = false; for (let i in new_assignment_ls) { if (course.CourseName == new_assignment_ls[i][3] && course.Semester == new_assignment_ls[i][4].split(' ').slice(1).join(' ') && course.Route == new_assignment_ls[i][5].split(' ').slice(1).join(' ')) { dataHtml += `<tr class='accordion' onclick="newAssign(this)"><td>${new_assignment_ls[i][0]}</td><td>${new_assignment_ls[i][1]}</td><td>${new_assignment_ls[i][2]}</td><td>${course.Year}</td><td>${course.Semester}</td><td>${course.Route}</td><td>${course.CourseName}</td></tr>`; isMatched = true; break; } } if (isMatched) { // 正确传入索引和删除数量,删除当前匹配项 department_arr.splice(idx, 1); } else { dataHtml += `<tr class='accordion' onclick="newAssign(this)"><td></td><td></td><td></td><td>${course.Year}</td><td>${course.Semester}</td><td>${course.Route}</td><td>${course.CourseName}</td></tr>`; } }
内容的提问来源于stack exchange,提问作者Sasson Gabai
相关产品推荐
相关产品推荐

