0

I've ran into something in JavaScript that goes completely against my intuitions. I first define a function, Shuffle(Input_array), that randomizes the order of an array. I then define an array, Words, print it to the console, and then print the result from Shuffle(Words).

This is the code:

<script>
function Shuffle(Input_array) {
  var currentIndex = Input_array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = Input_array[currentIndex];
    Input_array[currentIndex] = Input_array[randomIndex];
    Input_array[randomIndex] = temporaryValue;
  }
  return Input_array;
}

var Words = [["I","think"],["this","is"],["very","strange"]];
console.log(Words);
console.log(Shuffle(Words));
</script>

When running this script, both my calls generate the same output, namely a shuffled array. When commenting out the last console.log command, however, the array is printed in the order I defined it.

How is this possible? It seems like the first console.logoutput is affected in whatever happens in the second one.

It should be noted that this doesn't happen if I define my array in a 1D fashion, for example var Words = ["This", "actually", "works"];. I don't know if my function somehow can't handle 2D-arrays, but this shouldn't matter at all, since a later function call shouldn't be able to affect an operation predating it.

Speldosa
  • 1,900
  • 5
  • 21
  • 36
  • This is an artifact of the way the console shows arrays. For a multi-dimensional array it doesn't show the contents until you expand it. And you're not doing that until after you call `Shuffle()` which has changed the order. – Barmar Mar 05 '18 at 20:28
  • Look at [this CodePen](https://codepen.io/dnc042/pen/KQjVXj) your code works if you output to HTML divs – jmbmage Mar 05 '18 at 20:33
  • You didn't comment out the second `console.log` call, you commented out the `Shuffle` call - that's the one that changes the `Words` array – Bergi Mar 05 '18 at 20:36

2 Answers2

4

The Javascript console contains a live copy of the array, not a snapshot of the contents when you called console.log(). The Shuffle() function modifies the array in place. If you expand the contents of the first log of the array after you call Shuffle(), it shows the current contents, which are in shuffled order.

The reason this doesn't happen with a 1D array is because then console.log() shows the contents immediately, rather than waiting for you to click on the disclosure triangle.

If you set a breakpoint between the two calls you can view the original, unshuffled contents of the array. Or you could use console.log(JSON.stringify(Words)) to view a snapshot in text format.

Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    Okay, I see. When placing `console.log(Words[0][0]);` in between the other two `console.log()` calls, I always get the same (correct) result, meaning at least the variable is not manipulated internally before the function call. – Speldosa Mar 05 '18 at 20:43
1

It's working as intended because you're modifying the input array. In Javascript, all objects have a reference in memory, and if you modify it without creating a new instance of the object beforehand you're changing your "original" object.

And arrays are basically objects, so the same principle is applied to them.

To fix your shuffle method you need to create a new instance instead of directly manipulating your input array.

function Shuffle(Input_array) {
  Input_array = Input_array.slice(); // creates a new instance in memory
  var currentIndex = Input_array.length, temporaryValue, randomIndex;

  // While there remain elements to shuffle...
  while (0 !== currentIndex) {

    // Pick a remaining element...
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;

    // And swap it with the current element.
    temporaryValue = Input_array[currentIndex];
    Input_array[currentIndex] = Input_array[randomIndex];
    Input_array[randomIndex] = temporaryValue;
  }
  return Input_array;
}

var Words = [["I","think"],["this","is"],["very","strange"]];
console.log(Words);
console.log(Shuffle(Words));
console.log(Words !== Shuffle(Words));
cyr_x
  • 13,987
  • 2
  • 32
  • 46
  • @Barmar's answer is better. The question asks why the output is affected by a subsequent operation and it has more to do with the behavior of the logger and less to do with the data being provided to `console.log`. – tresf Mar 05 '18 at 20:44
  • 1
    Yep, I'm with you. I realized it after my answer but i think it also provides some information whats going on because it's explaining some more details behind it. – cyr_x Mar 05 '18 at 20:45
  • 1
    Agreed, the `.slice()` adds value to the question however you're also making an assumption the OP *doesn't* want that behavior, which is inconclusive at this point. – tresf Mar 05 '18 at 20:49
  • You're right I indeed assumed that he doesn't want that behavior because i was reflecting the question from a point of view where immutable data is the key to success, that was my mistake. – cyr_x Mar 05 '18 at 20:58