简体   繁体   English

JavaScript - 使用 Array.prototype.splice 从数组中删除元素时出现意外结果

[英]JavaScript - Unexpected result while remove elements from an array using Array.prototype.splice

i know this is an annoying question, but can someone explain me why splice method is executing in a weird way.我知道这是一个烦人的问题,但有人可以解释一下为什么 splice 方法以一种奇怪的方式执行。 Please explain me why the expected output is different from the actual result.请解释一下为什么预期的 output 与实际结果不同。


let numbers = [15, 12, 15, 3, 5, 4, 6];

// Get the indexes of the numbers greater than 5
let indexes = numbers.reduce((arr, current, index) => {
  if (current > 5) {
    arr.push(index);
  }

  return arr;
}, []);

// Loop through the indexes while removing the indexes from the numbers array
indexes.forEach((element) => {
  numbers.splice(element, 1);
});

// expected result: numbers = [ 3 , 5, 4 ];
// actual result: numbers = [ 12, 3, 4, 6 ]

.splice() changes the array it is used on. .splice()更改它所使用的数组。 You might have already known this, but if you debug your code using a console.log , you'll see what's happening;您可能已经知道这一点,但是如果您使用console.log调试代码,您会看到发生了什么; in short, your first number > 5 is 15. 15 is at index 0, so you remove index 0. However, as splice changes the array it is used on, 12 becomes index 0, and then the second 15 index 1, and so on and so forth.简而言之,您的第一个数字 > 5 是 15。15 在索引 0 处,因此您删除索引 0。但是,随着 splice 更改它所使用的数组,12 变为索引 0,然后第二个 15 变为索引 1,依此类推等等。 So for example, your code has the following indexes: 0, 1, 2, 6.例如,您的代码具有以下索引:0、1、2、6。

  • The first time you remove index 0: [12, 15, 3, 5, 4, 6]第一次删除索引 0: [12, 15, 3, 5, 4, 6]
  • Then you remove index 1: [12, 3, 5, 4, 6]然后你删除索引 1: [12, 3, 5, 4, 6]
  • Then you remove index 2: [12, 3, 4, 6]然后你删除索引 2: [12, 3, 4, 6]
  • Then you remove index 6, which doesn't exist: [12, 3, 4, 6]然后删除不存在的索引 6: [12, 3, 4, 6]

The better way of accomplishing that goal is with .filter() .实现该目标的更好方法是使用.filter() Filter creates a new array of all items that pass the test given in the callback, so:过滤器创建一个新数组,其中包含通过回调中给出的测试的所有项目,因此:

numbers = numbers.filter((num) => num < 6);

That's the arrow function expression shorthand to return only numbers less than 6.这是箭头 function 表达式简写,只返回小于 6 的数字。

splice actually removes the item in place . splice 实际上删除了该项目 It does not create any copy of array.它不会创建任何数组副本。 In your case after reduce operation, indexes would be在您的情况下,减少操作后,索引将是

 [0, 1, 2, 6]

and then while iterating and splicing, in first iteration array with position 0 is removed so array becomes然后在迭代和拼接时,在第一次迭代数组中 position 0 被删除,因此数组变为

numbers = [12, 15, 3, 5, 4, 6];

and its length is also reduced.它的长度也减少了。 On next iteration of forEach array element with index position 1 is removed which is 15 in our case.在 forEach 数组元素的下一次迭代中,索引为 position 1 被删除,在我们的例子中为 15。 So after second iteration array becomes所以在第二次迭代数组变成

    numbers = [12, 3, 5, 4, 6];

Similarly in next subsequent iteration you will have result like同样,在下一次后续迭代中,您将得到类似的结果

[12, 3, 4, 6]

As someone has mentioned the problem is with applying changes over an array that is mutated in every iteration.正如有人提到的那样,问题在于在每次迭代中都会发生突变的数组上应用更改。

I assume the example is for learning purposes as it would have been easier to write it like:我假设这个例子是为了学习目的,因为这样写起来会更容易:


let numbers = [15, 12, 15, 3, 5, 4, 6]
numbers.filter(elem => elem <= 5) 

In any case, and following the demonstration code, it would be good to stress the dangerous of mutations that is prone to spooky effects.在任何情况下,按照演示代码,最好强调容易产生怪异影响的突变的危险。 I have rewritten the code in a more functional style:我以更实用的风格重写了代码:

 let numbers = [15, 12, 15, 3, 5, 4, 6]; // Get the indexes of the numbers greater than 5 let indexes = numbers.reduce((arr, current, index) => { if (current > 5) { return arr.concat(index); } return arr; }, []); // Instead of removing we create a new array filtering out the elements we dont want let filteredNumbers = numbers.filter((_,index) => indexes.indexOf(index) === -1) console.log(filteredNumbers) // expected result: numbers = [ 3, 5, 4 ]; // actual result: numbers = [ 3, 5, 4 ]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM