1

I'm doing some string manipulation by splitting the string using .split(''), then iterating through it with a for loop, then using .join('') to reassemble it. I coded the split, loop, and join, and everything worked fine. But I decided to do another for loop operation on the string before the loop I already had, but after the split, and I ran into this. Before I even get to the loop, those values are showing up in the array! What is going on?

Here's a sample program showing the problem stripped to bare bones.

var someFunction = function () {
    var foo = '';

    foo = foo + 'Hello, world!';

    console.log(foo);

    console.log(foo.split(''));

    foo = foo.split('');

    console.log(foo); //  <-- This is the call causing me issues

    for(var i = 0; i < foo.length; i++) {
        foo[i] += 'bar';
    }

    foo = foo.join('');

    console.log(foo);
};

someFunction();

This outputs:

Hello, world!
Array(13) [ "H", "e", "l", "l", "o", ",", " ", "w", "o", "r", … ]

Array(13) [ "H", "e", "l", "l", "o", ",", " ", "w", "o", "r", … ] //<-- This is the marked console.log call

    [
    0: "Hbar"    //<-- This is the array expanded so you can see the values inside
    1: "ebar"
    2: "lbar"
    3: "lbar"
    4: "obar"
    5: ",bar"
    6: " bar"
    7: "wbar"
    8: "obar"
    9: "rbar"
    10: "lbar"
    11: "dbar"
    12: "!bar"
    ]

Hbarebarlbarlbarobar,bar barwbarobarrbarlbardbar!bar

It's really stumping me!

  • 1
    The console evaluates the content of the array when you expand it. If you want to see the content at the time of execution use `console.log(JSON.stringify(foo))` – Andreas Mar 07 '20 at 13:44
  • 1
    When you log an object (such as an array) with `console.log`, the log keeps a reference to the object. If you expand the object in the log later, you see its contents as they are **then**, not earlier when it was logged. See the linked questions' answers for details. – T.J. Crowder Mar 07 '20 at 13:44
  • Just FWIW, if you want to add something after every character in a string, you don't have to `split`, `for`, and `join`, you can use `replace`: `"Hello world".replace(/./g, "$&bar")` results in `"Hbarebarlbarlbarobar barwbarobarrbarlbardbar"`. – T.J. Crowder Mar 07 '20 at 13:46
  • Interesting. So I could workaround it using ```console.log(JSON.stringify(foo))```, like Andreas said, or I could store ```foo``` in an intermediate variable, and log that, like ```var fooSansBar = foo;```, then ```console.log(fooSansBar);``` – ToTheStars_1138 Mar 07 '20 at 13:48
  • No, you’d need to *copy* it into a new value, otherwise you just have two references to the same data. – Dave Newton Mar 07 '20 at 13:50
  • @DaveNewton Wait, you're saying that ```var fooSansBar = foo;``` isn't storing the _contents_ of ```foo``` into ```fooSansBar```, it's still storing a reference to the current state of ```foo```? – ToTheStars_1138 Mar 07 '20 at 13:53
  • @T.J.Crowder I appreciate it! In the actual application, I'm not adding something after every character, I'm actually adding a random number of things after a random number of characters at random places in the string... but I'll keep that solution in mind for later! – ToTheStars_1138 Mar 07 '20 at 13:55
  • @ToTheStars_1138 https://stackoverflow.com/questions/7486085/copy-array-by-value – VLAZ Mar 07 '20 at 13:58
  • Aha! Wow, that is helpful to know, and probably explains hours of debugging pain I've previously undergone. Thank you everyone for your quick and helpful replies! – ToTheStars_1138 Mar 07 '20 at 14:06

0 Answers0