0

I want to push items in a list using a for loop and print every step with a delay. Instead I get in every iteration the complete list.I guess this is a scope problem but I cant figure a solution.

Here is my code:

function printNumber(num,i){

    setTimeout(()=>console.log(num),500*i);
}


let numbers = [50];

for(let i=1; i<=10; i++){

    printNumber(numbers,i);
    numbers.push(i);
}


4 Answers4

0

You hand over the array instead of the value.

printNumber(i, i);
//          ^

function printNumber(num, i) {
    setTimeout(() => console.log(num), 500 * i);
}

let numbers = [50];

for (let i = 1; i <= 10; i++) {
    printNumber(i, i);
    numbers.push(i);
}

If you like to show all collected numbers, you could take a copy of the array.

function printNumber([...num], i) {
    setTimeout(() => console.log(...num), 500 * i);
}

let numbers = [50];

for (let i = 1; i <= 10; i++) {
    numbers.push(i);
    printNumber(numbers, i);
}
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
0

I think you might be looking for something like in the below snippet. The array includes all values every iteration because the loop runs to completion before the setTimeout starts printing things.

Since arrays are stored as references, num is being mutated by numbers.push(i).

Passing the function a new array each loop will solve this.

function printNumber(num,i){

    setTimeout(()=>console.log(num),500*i);
}


let numbers = [50];

for(let i=1; i<=10; i++){
    // Create new array when you pass it here
    printNumber([...numbers],i);
    numbers.push(i);
}
Brian Thompson
  • 13,263
  • 4
  • 23
  • 43
0

That's because Javascript passes arrays by reference*, which means that the callback, which runs long after the loop is concluded, will all point to the same, updated, value of the array.

You need to copy the array every time to use the intermediate state. You can call printNumber this way:

printNumber([...numbers], i);

So that it will make a new copy of the array and iterations won't mess with each other.

* see Brian Thompson's comment for further clarification

ranieri
  • 2,030
  • 2
  • 21
  • 39
  • 1
    Your solution is correct but your link title is wrong. JavaScript is always pass-by-value, not reference. In fact, one of the top answers in the question you linked explains this. The *value* held in variables for objects (including arrays) *is* a reference. So it still passes the *value*, but the the value is a reference. Its almost the same effect, except it means that accidental mutation can happen without ever passing it to a function. – Brian Thompson Mar 13 '20 at 13:08
  • 1
    @BrianThompson correct! Edited my answer to reference your comment (no pun intended) – ranieri Mar 16 '20 at 22:23
0

setTimeout is a timer. It will execute anything INSIDE with a delay. It doesn't pause the rest of the code. By the time console.log execute your array is complete. So it will print the completed array.

let numbers = [50];

for(let i=1; i<=10; i++){
     
     setTimeout(()=>{  
       console.log(numbers, i)
       numbers.push(i); 
       
     },500*i);
}
MonteCristo
  • 1,471
  • 2
  • 20
  • 41