Reputation: 243
I am new to JavaScript, and recently stumbled across this problem questioning what would be printed to the console. The correct answer is 4 4 4 4
, because of pass-by-reference. However, I don't understand how this is the result. Why does pass-by-reference dictate the output if the output is simply a value of i
that seems only dependent upon an iteration of a for-loop
?
const array = [10, 21, 31, 41];
for(i = 0; i < array.length; i++) {
setTimeout(function print(array){
console.log(i)}, 3000);
}
Upvotes: 0
Views: 35
Reputation: 32176
Okay, step by step:
const array = [10, 21, 31, 41];
for(i = 0; i < array.length; i++) {
setTimeout(function print(array) { /* stuff... */ }, 3000);
}
// When we get to here, the value of i is 4.
When this snippet runs, we iterate the array, and set a timeout for each iteration. When the for loop is finished, we have called setTimeout
four times, but none of the functions given to setTimeout
have run. Indeed, they won't run for another 3 seconds.
Most importantly, at this point, the value of i
is 4
.
Three seconds later...
Finally, our function print
that we gave to setTimeout
is going to run. So what does that function look like?:
function print(array) { console.log(i); }
Now recall the value of i
is now 4. So it prints 4
, four times. This is because it is when the function actually executes that it reads the value of the variable i
, not when the function was declared.
Basically, i
is 4 at the time that your function print
is actually invoked, so therefore, it unsurprisingly prints 4
.
Upvotes: 2
Reputation: 118
To be able to use 'i' value you need something called closure. When the function execute at that time i value became 4 and it gets printed.
Upvotes: 0
Reputation: 18569
There's only a single value of i
. Calling setTimeout
doesn't store the original value anywhere.
Because the print
function is called after the for-loop has finished running, the value of i
will be 4
because it's the value it'll have at the end of the for-loop.
Upvotes: 0
Reputation: 209
Look again at the inner function which is being called by the timeout.
function print(array){
console.log(i);
}
At no point is the passed in array actually used for anything, in fact the following code will do exactly the same thing (print 4 4 4 4)
for(i = 0; i < array.length; i++) {
setTimeout(function print(){
console.log(i)}, 3000);
}
The pass by reference part means that it isn't the value of i which is passed in to the print() function, but a reference to whatever value is held by i at the time console.log(i) is called. Since there is a 3 second delay, the loop has more than enough time to finish and the value of i is 4 by the time the first console.log(i) is called. You can even set the value of i after the loop and it will change the result.
for(i = 0; i < 4; i++) {
setTimeout(function print(){
console.log(i)}, 3000);
}
i = "foo";
// prints foo foo foo foo
Upvotes: 1
Reputation: 1287
Your setTimeout makes your code async, wenn the timeout of 3000 is gone the javascript loop is ended before and the last value of the index will be toke also the number 4. Search for 'js Eventloop' and you will discover more about, how the Browser works in a nutshell.
Upvotes: 0