23
var arr = ['Foo'];

arr.forEach(function(item){
  console.log(item);
  item = 'Lorem';
  console.dir(arr[0]);

});

for (var item in arr){
  arr[item] = 'Ipsum';
  console.dir(arr[0]);
}

Like the code above shows, I noticed that changing the value of an item passed to the callback of forEach() does not cause the iterated object to alter.

Using for...in certainly does.

Why is that & how should I alter values in an array?

I find that the topic is covered quite confusing on MDN

DanZimm
  • 2,528
  • 2
  • 19
  • 27
Wottensprels
  • 3,307
  • 2
  • 29
  • 38
  • The order in which properties are visited in [*for..in*](http://ecma-international.org/ecma-262/5.1/#sec-12.6.4) is entirely implementation dependent. [*forEach*](http://ecma-international.org/ecma-262/5.1/#sec-15.4.4.18) visits only numeric properties from 0 to *length* and strictly in numeric order, it has nothing to do with the value. The link to MDN is broken, perhaps you meant [this one](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach). – RobG May 30 '14 at 22:17
  • 4
    Would you ***please*** put your code here instead of on some other site? – cookie monster May 30 '14 at 22:19

3 Answers3

28

Using for...in certainly does.

No it doesn't. Your forEach loop is equivalent to this for...in loop (apart from the order):

for (var index in arr) {
  var item = arr[index];
  console.log(item);
  item = 'Lorem';
  console.dir(arr[0]);
}

Do you see that the array isn't modified either? That's because JavaScript is always pass-by-value, and there is a very simple rule to keep in mind:

Assigning a value to a variable never changes the value of another variable or data structure.

That means, assigning a new value to item, cannot change an element of arr. If you want to to modify the array, you have to mutate it directly by assigning a value to an index, i.e.

arr[index] = 'foo';
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
  • 8
    I find that this sounds confusing as objects **are** passed by reference – Wottensprels May 31 '14 at 08:00
  • 1
    @Sprottenwels: No. This is correct. JavaScript only has pass-by-value. The only values in JavaScript are primitives and pointers to objects. "Objects" are not values and cannot be "passed". – newacct May 31 '14 at 09:46
  • @Sprottenwels: It is confusing, but *pass-by-reference* has a different and very specific meaning. You can read about in the Wikipedia article. Also have a look at the section *pass-by-sharing*, which is closer to how JS works, but it's not a very common term. – Felix Kling May 31 '14 at 22:16
17

In your case, the item variable is passed by value, because it is of a primitive value. If it were a json object, and you would change one of its properties, it would be reflected on the original list.

In this situation, you can use other arguments that the forEach has. For example:

arr.forEach(element, index, array) {
    ...
}

Using these arguments, you can affect directly array[index]

tigermarques
  • 187
  • 1
  • 6
13

Notice that callback in forEach gets three arguments. The second one being an index of current element, and the third one the array itself. If you want to modify the array, use these two arguments.

Mchl
  • 61,444
  • 9
  • 118
  • 120