2

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!!

Diogo Santos
  • 780
  • 4
  • 17
  • @BrandonHill not for `forEach` -- OP would have to use `map` (which they probably should). – ggorlen Apr 13 '21 at 16:08
  • Does this answer your question? [change values in array when doing foreach](https://stackoverflow.com/questions/12482961/change-values-in-array-when-doing-foreach) – ggorlen Apr 13 '21 at 16:10

6 Answers6

2

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);
Ravi Chaudhary
  • 660
  • 6
  • 22
2

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);
jnpdx
  • 45,847
  • 6
  • 64
  • 94
  • 1
    Keep in mind that if `test` is massive, this makes a copy of `test` and then throws the original `test` to the garbage collector so there is a memory hit for the non-inplace operation. 98% of the time this is what you want though. – ggorlen Apr 13 '21 at 16:09
2

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.

Kai Lehmann
  • 508
  • 4
  • 17
1

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);
Rojo
  • 2,749
  • 1
  • 13
  • 34
1

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";
});
Nisala
  • 1,313
  • 1
  • 16
  • 30
-2

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]
junvar
  • 11,151
  • 2
  • 30
  • 46