4

I want to swap two arrays inside a 2D array, however JS seems to be doing that before my actual swap is happening.

This is for an algorithm I'm working on, providing each possible way to display a list of points. I have tried several ways of doing this, but the key problem keeps returning, and I've managed to crop it down to this peace of code:

var points = [[1,2],[10,20],[100,200]];
console.log(points);
var a = points[1][0];
var b = points[1][1];
points[1][0] = points[2][0];
points[1][1] = points[2][1];
points[2][0] = a;
points[2][1] = b;
console.log(points);

I know this code isn't close to being DRY, but it has the same problem: 'points' is logged to the console in the line after being declared, though in that log, it is already swapped? How is that possible, as there were no commands yet saying it to do so. How does JavaScript handle this peace of code? And why doesn't mine seem to be working?

**The expected output for the first log is: [[1,2],[10,20],[100,200]] **and for the second log: [[1,2],[100,200],[10,20]]

The StackOverFlow snipped runs it as it is expected, but Chrome runs it differently

sideshowbarker
  • 81,827
  • 26
  • 193
  • 197

2 Answers2

8

I believe what's happening here is that the console is showing something like this (in Firefox):

initial console

But then you click to expand it to take a look inside the array, the items are swapped:

expanded console

This is because the console is actually showing you a reference to the array, and since your algorithm modifies the original array in place, by the time you click to expand the element in console, the reference has been modified. Your code is fine, you might try using .toString() or JSON.stringify or even [...points] to make sure what's output to the console in each line are different values and not a reference to the same value.

Running your exact algorithm with console.log(points.toString()) instead, I see this (again in Firefox):

toString demo

And just for demonstration purposes, here's how you can simplify your code to do the same thing using destructured assignment:

var points = [[1, 2], [10, 20], [100, 200]];
console.log(points.toString());
[points[1], points[2]] = [points[2], points[1]];
console.log(points.toString());
p.s.w.g
  • 146,324
  • 30
  • 291
  • 331
  • Out of curiosity, what environment are you using to reproduce this? Also, it might be interesting to demonstrate the change happening after the call to console.log using a setTimeout. – 3ocene Feb 14 '19 at 18:58
  • @3ocene Firefox (I initially said Chrome because that's what I usually use but I just realized I'm using Firefox ATM), but you get the same results in Chrome. You can reproduce it by just running OP's original snippet with the dev tools open. – p.s.w.g Feb 14 '19 at 19:01
  • 1
    Ah, I wasn't familiar with the color scheme; thought it was an IDE. I decided to try it myself in Chrome to see what happens. It looks like the console.log is a reference until you expand it and then it changes to be a value. Using a setTimeout, if you expand the log message before the timeout executes it shows the initial value—and stays as that value even after the timeout runs—and if you expand it after it executes you get the second value. TIL. – 3ocene Feb 14 '19 at 19:05
  • Thanks a lot! The desired output is achieved using .toString(). I just couldnt find the error in my code. – Stijn van Balen Feb 14 '19 at 19:08
0

p.s.w.g is correct, this has to do with Chrome's lazy eval of arrays for things like console.log. Here's more detail: Is Chrome's JavaScript console lazy about evaluating arrays?

javazen
  • 171
  • 1
  • 2
  • 8
  • 2
    This would probably be better suited as a comment. Answers that just say someone else is correct don't contribute any more than an upvote does. Additionally, it would be preferable to include the essential parts from that link here and provide the link for reference since links often change and break. – 3ocene Feb 14 '19 at 19:19