我试图根据另一个数组中不存在的索引从数组中删除一个单词,但我在使用拼接和过滤方法时观察到了奇怪的行为.

有人能解释一下下面的情况吗?Why is it happening like this in both cases, even though the same object is being altered on iteration?

Words

['one', 'two', 'three', 'four', 'five', 'six', 'seven']

Removable Words

['four', 'two', 'eight']

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)
  }
});

/* Output */
//one
//two
//three
//four
//five
//six
//seven

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);
  }
});

/* Output */
//one
//two
//four
//six
//seven

如本Mozila document-forEach() does not make a copy of the array before iterating.中所述,在过滤并分配回原始对象后,它的行为不应该与拼接相同吗?

Note:除此之外,拼接方法对原始数组进行更改,过滤方法创建数组的新副本,并且不改变原始数组,但在给定示例中(过滤后),结果被分配回原始array.

推荐答案

Your first example also works, but your console.log may confuse you. You log once for every word in the for loop before filtering.
Just log the result words after the loop to see that it works.

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

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

console.log(words);

Answer to the OPs comment:
So I guess, that you are confused by

"forEach()在迭代之前不复制数组"

  • 的确,forEach()不能复制:但you在循环内复制
  • 在开始时,变量words是对原始数组['one', 'two', 'three', 'four', 'five', 'six', 'seven']的引用
  • 现在调用words.forEach(),这是一个在该数组上返回迭代器的函数(迭代器将始终指向该原始数组,无论您稍后是否更改words个引用点的位置)
  • 在循环中,您使用words.filter(例如['one', 'two', 'three', 'five', 'six', 'seven'])创建一个新数组,并将words变量更改为指向此新数组-但这不会更改您之前创建的迭代器:即forEach循环仍然"指向"原始数组

对于第二个示例:

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

  • 同样,forEach不会复制
  • 迭代器将指向原始数组
  • but now you change the original array, inside of your loop: i.e.
    • 当循环到达索引1处的单词"two"时,将原始数组更改为['one', 'three', 'four', 'five', 'six', 'seven']
    • 换句话说:删除索引1处的项,其他项向左移动
  • 现在迭代器将继续,下一个索引是2
  • 注意,循环中的console.log:可以看到iterationArray发生了变化

Javascript相关问答推荐

如何解决CORS政策的问题

Google图表时间轴—更改hAxis文本 colored颜色

React 17与React 18中的不同setState行为

如何在angular中从JSON值添加动态路由保护?

将自定义排序应用于角形数字数组

colored颜色 检测JS,平均图像 colored颜色 检测JS

有没有可能使滑动img动画以更快的速度连续?

在forEach循环中获取目标而不是父对象的属性

Eval vs函数()返回语义

连接到游戏的玩家不会在浏览器在线游戏中呈现

查询参数未在我的Next.js应用路由接口中定义

使用Ace编辑器对子组件实例的native-element 进行Angular 获取时面临的问题

当标题被点击时,如何使内容出现在另一个div上?

JavaScript:如果字符串不是A或B,则

更改agGRID/Reaction中的单元格格式

在Press Reaction本机和EXPO av上播放单个文件

验证Java脚本函数中的两个变量

鼠标进入,每秒将图像大小减小5%

如何让noWrap在嵌套在Alert/AlertTitle组件中的排版组件中工作?

使用EXCEL.js模块+node.js分隔标题行中的列