Understanding the difference depends on understanding the fact that splice
will change the length of the array you’re calling it on. This isn’t going to be easy for me to write about, and it’s going to be just as hard for you to understand, so you need to really think this through. Let’s first read the loop construct for the code that doesn’t work:
for (var x = 0; x < newArr[0].length; x++)
x
starts at 0. While x
is less than the length of the array at newArr[0]
, keep running the loop. At the end of each loop, increment x
by 1. Note that the loop gets newArr[0].length at each iteration. If the length of the array changes, so do the loop’s parameters.
Now think about what happens in this loop the first time it gets a match. Let’s say we’ve called destroyer([2, 3, 2, 3], 2, 3)
, so newArr[0]
is [2,3,2,3]
and arr
is [2,3]
. We start both loops at 0, and the first number we want to destroy is 2 (arr[0]
is 2);
// x === 0 and i === 0
if (newArr[0][x] == arr[i]) newArr[0].splice(x,1);
// same thing as
if(2 == 2) newArr[0].splice(x,1);
// so the array gets spliced
[2,3,2,3].splice(0, 1); // [3,2,3] <= newArr[0] has been changed.
After the first item has been destroyed, x
increments to 1. The same thing happens because newArr[1]
is 2, so it happens to delete another number. Now the array is [3,3]
. The length of the array started at 4, but now it’s 2. x
increments to 3, and while this wouldn’t have ended the loop when we started, since the array is shorter the inner loop ends.
The outer loop increments - i
is 1. We’re now looking to destroy 3 since that’s the value at arr[1]
. This is where the code breaks down.
// x === 0 and i === 1
if(newArr[0][x] == arr[i]) newArr[0].splice(x,1);
// same thing as
if(3 == 3) newArr[0].splice(x,1);
// the array gets spliced again
[3,3].splice(0, 1); // [3] <= newArr[0] has been changed
Now newArr
's length is 1. The array only contains the number 3, which should be deleted, right?
WRONG
Because newArr
has only one value, its index is 0. We just got done destroying the 0th item. The loop increments and we’re now looking at x
=== 1 and i
=== 1. Both loops are done and the function returns an array with a single value, [3]
.
The reason the other code works is because you’re editing newArr
from the end and decrementing the inner loop. newArr
's length still changes, but since we’re counting from the back and working towards 0, it doesn’t matter. Imagine chopping down a tree by chunks. The broken code is the same as starting from the roots and moving up. As you chop a chunk, you shorten the tree from the bottom. The code that works is like chopping chunks off the tree from the top.
You’re probably not going to understand the problem just by reading this mess. I know that I wouldn’t. The only way this is going to click is if you walk through to code yourself, methodically and slowly. Talk out loud. Pretend you’re explaining the code to a small child or a rubber duck. This is how you really learn to code, and there are no shortcuts.