KekmasterACR
KekmasterACR

Reputation: 154

Why for... of loop doesn't change values inside the array, while the regular for loop does?

Consider the following code.

const iterable = [10, 20, 30];

for (let value of iterable) {
  value += 1;
  console.log(value);
}

// 11
// 21
// 31

console.log(('after for...of'), iterable); // [10, 20, 30] - no change

const iterable1 = [10, 20, 30];

for (let i = 0; i < iterable1.length; i++) {
  iterable1[i] += 1;
  console.log(iterable1[i]);
}

// 11
// 21
// 31

console.log(('after regular for...'), iterable1); // [11, 21, 31] - values changed

As you see and as was stated in the question, the values in the array didn't change after the for...of loop, but did after the regular for loop.

After reading this article on MDN about the for... of I was led to believe that(at least in this particular context) it would be identical to the for loop, but as you see, this has proven not to be the case. It is especially baffling for me since the article states that

It invokes a custom iteration hook with statements to be executed for the value of each distinct property of the object.

The article proceeds to state that you can reassign values of the iterable(in our case, an array) inside the block.

You can use let instead of const too, if you reassign the variable inside the block.

It would seem to me that I lack some critical (maybe even trivial) insight into how the for...of works, and I hope you could help me better understand what is going on.

Upvotes: 0

Views: 2560

Answers (3)

tonitone120
tonitone120

Reputation: 2300

Might be helpful to look at a for...of loop as similar to a function.

Remember, in a function when you pass in an argument that is a primitive data-type, the parameter for that argument will receive a 'copy' of that argument's primitive value. Any changes made to the parameter will not effect the outside variable|argument.

And, when you pass in an argument that is an object, the parameter for that argument gets a copy of the address in memory of the object e.g. it will refer to the same object. Any changes made to the parameter will effect the outside variable|argument.

The code snippet below demonstrates these two ideas:

primitiveVariable = 1;
obj = {num: 1};

function f(primitive, object) {
  primitive+=1;
  object.num+=1;
  console.log(primitive);
  console.log(object)
}

f(primitiveVariable, obj);

console.log(primitiveVariable);
console.log(obj);

A for...of loop operates the same:

a = [1, 2, 3];

for (item of a) {
  item += 1;
}

console.log(a);

for (item of a) {
  a[0] = item;
}

console.log(a);

Upvotes: 2

brk
brk

Reputation: 50291

In the first case you are just accessing the value but after after increment you are not setting it back to the array. Since array index is not available while using for...of you can use entries

const iterable = [10, 20, 30];

for (const [i, v] of iterable.entries()) {
  iterable[i] = v + 1
}
console.log(('after for...of'), iterable);

Upvotes: 2

Pointy
Pointy

Reputation: 413737

In your for ... of loop, on each iteration value is a copy of an element in the array. Thus,

value += 1;

is critically different from

iterable1[i] += 1;

The value += 1; statement does work, and after that value will indeed contain a number one greater than an element of the array. However, the element of the array itself remains unchanged.

Consider this simpler case:

let x = 0, y;

y = x;
y += 1;
console.log(x);

you would see no change to the value of x. The variable y is also just a copy of the value of x, so when y changes, x is unaffected.

Upvotes: 4

Related Questions