You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JavaScript中forEach删除元素出现异常行为的原因解析

数组迭代中splice与filter赋值的行为差异解析

我尝试从一个数组中移除存在于另一个数组中的元素,但在使用splice和filter方法时观察到异常行为,想请教:为何两种情况会出现这样的表现,明明在迭代时修改的是同一个对象?

相关数组定义:

  • Words数组:['one', 'two', 'three', 'four', 'five', 'six', 'seven']
  • 待移除单词数组:['four', 'two', 'eight']

代码示例1:forEach结合filter赋值

let words = ['one', 'two', 'three', 'four', 'five', 'six', 'seven'];
let removedWords = ['four', 'two', 'eight'];

words.forEach((word) => {
  console.log(word);
  if (removedWords.includes(word)) {
    words = words.filter((removableWord) => removableWord !== word)
  }
});

/* 输出 */
//one
//two
//three
//four
//five
//six
//seven

代码示例2:forEach结合splice

let words = ['one', 'two', 'three', 'four', 'five', 'six', 'seven'];
let removedWords = ['four', 'two', 'eight'];
words.forEach((word, index) => {
  console.log(word);
  if (removedWords.includes(word)) {
    words.splice(index, 1);
  }
});

/* 输出 */
//one
//two
//four
//six
//seven

我注意到MDN文档提到:forEach()在迭代前不会复制数组,但在过滤后将结果赋值回原变量后,它的表现为何与splice不一致?

补充说明:splice方法会修改原数组,而filter方法会创建新数组副本且不修改原数组,但在上述示例中,过滤后的结果已赋值回原数组。


行为差异解释

代码示例1的原理

forEach在启动迭代时,会绑定当前数组的引用,后续迭代完全基于这个原始数组的元素集合和长度执行,不会受变量重新赋值的影响。

当你执行words = words.filter(...)时,只是把words变量指向了一个全新的数组对象,但forEach迭代的依然是最初的那个原始数组。哪怕后续words指向了新数组,迭代过程还是会遍历原始数组的所有7个元素,所以控制台会输出全部单词。

代码示例2的原理

splice是直接修改原始数组本身(包括元素内容和数组长度),forEach迭代时会动态读取数组的当前状态,但迭代的索引是按初始数组的顺序依次推进的:

  1. 索引0:元素one不匹配,输出one,数组无变化
  2. 索引1:元素two匹配,执行splice(1,1),数组变为['one','three','four','five','six','seven'],长度从7变为6
  3. 索引2:此时原数组索引2的元素是four(因为three前移到了索引1),输出four并执行splice(2,1),数组变为['one','three','five','six','seven'],长度变为5
  4. 索引3:当前数组索引3的元素是six,输出six
  5. 索引4:元素seven,输出seven
  6. 初始数组长度为7,但当前数组长度已变为5,索引5、6超出范围,迭代终止

这就导致迭代跳过了three和five,最终输出结果为one、two、four、six、seven。

核心差异总结

  • filter赋值:改变的是变量的引用,forEach绑定的是迭代启动时的原始数组,新数组对迭代过程无影响
  • splice操作:直接修改原始数组的内容和长度,forEach迭代时会使用数组的当前状态,但索引按初始序列推进,从而出现元素跳过的情况

内容的提问来源于stack exchange,提问作者Dip Parmar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 00:39:17