Issue with foreach and changing variables

Viewed 137

I am trying to, in a foreach statement, to modify each of the array elements, in this case by adding a string.

var test = [["A","B"],["C","D"]]

test.forEach(function(test2){
    test2 = test2.map(function(elem){
    return elem+"_NEW STRING"
  })
  console.log(test2);
})
console.log(test);

However, the final variable is still the same as the original, no changes are made to the array contents, even though the middle console.log prints correctly.

What am I doing wrong? This seems a simple issue but I can't make it work right...

Thanks in advance!!

6 Answers

forEach doesn't return anything and simply calls your callback function for every element. For your requirement, map would be a better choice

var test = [["A","B"],["C","D"]]

const test2 = test.map( cur => cur.map(ele => ele +"_NEW STRING"))
console.log(test2);

Although, if you don't want to create a new array and want to do this operation inline, you can do it with forEach like this

var test = [["A","B"],["C","D"]]

test.forEach( cur => {
    cur.forEach((ele, i) => cur[i] = ele +"_NEW STRING");
    return cur;
});
console.log(test);

forEach probably isn't the approach you want in this case. You probably want two maps that each return. You could shorten this into a one-liner, but I've left it a little more verbose so that it's easier to tell what's going on:

var test = [["A","B"],["C","D"]]

test = test.map(function(test2){
    return test2.map(function(elem){
        return elem+"_NEW STRING"
  })
})
console.log(test);

test2 is not a pointer, it's a variable. With test2 = test2.map you are overriding the local variable test2. You are not changing test's entry.

var test = [["A","B"],["C","D"]]

test.forEach((subArray, index, testArray) =>{
    testArray(index) = subArray.map(function(elem){
    return elem+"_NEW STRING";
  })
  console.log(test2);
})
console.log(test);

or simply

var test = [["A","B"],["C","D"]]
test = test.map(function(test2){
    return test2.map(function(elem){
    return elem+"_NEW STRING"
  })
})
console.log(test);

checkout https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach for more information.

To edit the original array, you need to use the index and access the actual array:

var test = [["A","B"],["C","D"]]

test.forEach(function(test2, i){
  test[i] = test2.map(function(elem){
    return elem+"_NEW STRING"
  })
  console.log(test[i]);
})
console.log(test);

This is because in a foreach, changing the individual element it gives you doesn't change the base array. Check out this question to learn more.

TL;DR from that question, though, you can make changes to your array like this, using the index:

test.forEach(function(part, index, theArray) {
  theArray[index] = "hello world";
});

JS variables (both primitives & objects) are always passed by value, similar to Java, and unlike cpp.

JS doesn't pass by copy, which would look like:

let a = {x: 0};
let b = a;
b.x = 1;
// a.x === 0 *IF* JS passed objects by COPY

Nor does JS pass by reference, which would look like:

let a = {x: 0};
let b = a;
b = {y: 1};
// a === {y: 1} *IF* JS passed objects by REFERENCE

Instead, JS passes by value, which looks like:

let a = {x: 0};
let b = a;
b.x = 1;
// a.x === 0
b = {y: 1};
// a === {x: 1}

And more examples

let x = [[[1]]];
let y = x[0]; // [[1]]
let z = y[0]; // [1]

y = [[2]];
console.log(x); // [[[1]]]
console.log(y); // [[2]]
console.log(z); // [1]

z = [3]
console.log(x); // [[[1]]]
console.log(y); // [[2]]
console.log(z); // [3]

y = x[0]; // [[1]]
z = y[0]; // [1]
y[0] = 2;
console.log(x); // [[[2]]]
console.log(y); // [[2]]
console.log(z); // [1]

Related