1

I am currently learning JavaScript. And I tried to use a foreach loop to update my elements in an array. But the problem is that the "console.log" result always been the same array as before. Below is the code. Can anyone help tell the problem?

var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
    19, 300, 3775, 299, 36, 209, 148, 169, 299,
    6, 109, 20, 58, 139, 59, 3, 1, 139
];

var addNum = function(element,index,array){
    if(element%3===0)
    {
        element += 100;
    }
};

test.forEach(addNum);
console.log(test);
York Gong
  • 31
  • 1
  • 1
  • 3

2 Answers2

8

That's because in JavaScript arguments are passed by value, not by reference.
So changing element argument does nothing.

In your case, it is better to use map, like this:

var addNum = function(element,index,array){
    if(element%3===0)
    {
        return element + 100;
    }

    return element
};

const result = test.map(addNum);
console.log(result);

If you really need to use forEach - you could do it like this:

var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
    19, 300, 3775, 299, 36, 209, 148, 169, 299,
    6, 109, 20, 58, 139, 59, 3, 1, 139
];

var addNum = function(element,index,array){
    if(element%3===0)
    {
        array[index] += 100;
    }
};

test.forEach(addNum);
console.log(test);

But this is, in my opinion, a bad practice.
forEach is designed for doing something with each element in an array without changing it, but map is specifically designed to create new array running a function on each element of the provided array.
Also see discussion here Is there a difference between foreach and map?

Angel Politis
  • 10,955
  • 14
  • 48
  • 66
Bsalex
  • 2,847
  • 1
  • 15
  • 22
  • Yeah maybe the one who answer was deleted a second ago – Art_Code Dec 30 '17 at 00:28
  • The shorter version I could successfully run on FireFox 57 is: const result= test.map(i=>i%3===0? i+100: i); – jmowla Dec 30 '17 at 00:33
  • 1
    Why is using `forEach` a bad practice exactly? Any reference to back this up? – Angel Politis Dec 30 '17 at 00:38
  • In forEach statement you have to change the state of a variable outside of the function, but map just creates a new copy of the array which has no side effect. if you run forEach multiple times, you'll get different answers – jmowla Dec 30 '17 at 00:48
  • 1
    Changing the value of the original array is not a side-effect, but the actual purpose of using `forEach` in that context. The OP never explicitly said they wanted to modify a shallow copy of the original array, instead of the original array itself. Calling it bad practice, because of that is at least misinformation. – Angel Politis Dec 30 '17 at 00:57
  • Judging by the context of the question and the code - using `forEach` here is a bad practice. – Bsalex Dec 30 '17 at 01:03
  • 2
    In your opinion; that's the point I'm trying to make. It's not like the programming world, in general, considers the use of `forEach` bad practice. You have to be careful with your wording when addressing someone new to the language. Besides, _`update my elements in an array`_ sounds to me like the OP wants to modify the original array. – Angel Politis Dec 30 '17 at 01:13
  • Ok, I've updated the answer, added: "in my opinion". But please note that everything I'm writing is only my opinion. – Bsalex Dec 30 '17 at 01:23
5

In your addNum function, element is just an argument. When you modify it , you are only modifying the value inside the function, not the actual element in the array.

To modify the array, you need to target the element:

var test = [12, 929, 11, 3, 199, 1000, 7, 1, 24, 37, 4,
    19, 300, 3775, 299, 36, 209, 148, 169, 299,
    6, 109, 20, 58, 139, 59, 3, 1, 139
];

var addNum = function(element, index, array) {
    if (element % 3 === 0) {
        array[index] = element + 100;
    }
};
test.forEach(addNum);
console.log(test);

Note that in JavaScript you can directly pass an anonymous function to forEach():

test.forEach(function(element, index, array) {
    if (element % 3 === 0) {
        array[index] = element + 100;
    }
});
Angel Politis
  • 10,955
  • 14
  • 48
  • 66
Sébastien
  • 11,860
  • 11
  • 58
  • 78