循环splice数组后如何重新计算位置,使元素C处于正确第三位?
问题:调整数组插入逻辑,让name为'c'的元素出现在预期位置
你现在碰到的问题是,运行给定的JavaScript代码后,name: 'c'的元素没出现在期望的第3位,反而跑到了第4位。先来看下原代码、当前输出和我们想要的结果:
原代码
const foo = [ { name: 'a', }, { name: 'b' } ] const bar = [ { name: 'c', position: [1, 3] }, { name: 'd', position: [2] } ] bar.forEach((item) => { item.position.forEach((pos) => { foo.splice(pos - 1, 0, item); }); }) console.log(foo);
当前输出
[ { name: 'c', position: [ 1, 3 ] }, { name: 'd', position: [ 2 ] }, { name: 'a' }, { name: 'c', position: [ 1, 3 ] }, { name: 'b' } ]
期望输出
[ { name: 'c', position: [ 1, 3 ] }, { name: 'd', position: [ 2 ] }, { name: 'c', position: [ 1, 3 ] }, { name: 'a' }, { name: 'b' } ]
问题根源分析
问题出在插入顺序和数组动态变化的冲突上:
- 代码先遍历
bar里的c,先把它插入到位置1(对应数组索引0),此时foo变成[c, a, b] - 接着处理
c的第二个插入位置3(对应索引2),这时候还没处理d的插入,插入后foo变成[c, a, c, b] - 最后处理
d的插入位置2(对应索引1),插入后foo就变成了[c, d, a, c, b]——这就导致c跑到了第4位,和预期不符。
简单来说,因为你先处理c的两次插入,再处理d的插入,而每次插入都会改变数组的长度和元素位置,导致后续插入的位置计算出现偏移。
修复方案
我们可以换个思路:先收集所有需要插入的位置和元素,然后按位置从大到小排序后再执行插入。因为从大索引往小索引插入时,前面的插入操作不会影响后面要插入的位置的准确性(大索引的位置不会被小索引的插入打乱)。
修改后的代码如下:
const foo = [ { name: 'a' }, { name: 'b' } ] const bar = [ { name: 'c', position: [1, 3] }, { name: 'd', position: [2] } ] // 第一步:收集所有待插入的项,把位置转为数组索引(pos-1) const insertions = []; bar.forEach(item => { item.position.forEach(pos => { insertions.push({ index: pos - 1, element: item }); }); }); // 第二步:按索引从大到小排序,避免插入时位置偏移 insertions.sort((a, b) => b.index - a.index); // 第三步:执行插入操作 insertions.forEach(({ index, element }) => { foo.splice(index, 0, element); }); console.log(foo);
运行这段代码后,输出就会和你的期望完全一致了。
内容的提问来源于stack exchange,提问作者Mr Pablo
相关产品推荐
相关产品推荐

