Why does this setTimeout code output the same value?

Asked 1 years ago, Updated 1 years ago, 32 views

When I ran this code, I got a strange result

functionprintFive(){
    for(vari=0;i<5;i++){
        setTimeout(function(){
            console.log(i);
        }, i*1000);
    }
}

printFive();

If you do this,

0
1
2
3
4

If you think is going to output slowly, it's actually

5
5
5
5
5

has come out.

jsfiddle

Why do you loop from 0 to 4, but only 5 appears?How can I get my way?

javascript

2022-09-30 20:29

4 Answers

See I want to define what happens when I click with the for statement

The answer is the same as this.
The value must be bound by an immediate function within the for statement. See here for more information.

http://mattn.kaoriya.net/software/lang/javascript/20110523124612.htm


2022-09-30 20:29

In such cases, it is easy to bind the value of i as with ({i:i}):

functionprintFive(){
    for(vari=0;i<5;i++) with({i:i}){
        setTimeout(function(){
            console.log(i);
        }, i*1000);
    }
}

jsfiddle

Description:

The closure (as other answers show) maintains a reference to variable i (rather than capturing the declared value).Therefore, if the contents of the outer i are rewritten after the closure is generated, the rewritten value can also be seen from the closure.Furthermore, if one closure rewrites variable i, another closure will also see its rewritten value.

where with({i:i}) creates an object called {i:i} for each loop (an object whose member i has the value of vari at that time).Then with(...) replaces the i visible from the closure with the member of the object generated for each loop.

(But no one else has this kind of answer...) I sometimes use this method, but is there a problem?…)

# This is my first post, but can I post like this?


2022-09-30 20:29

The above results are due to Closure.

Simply put, the variables that appear when a function is running are the same wherever it is, even if they are used by the function in it.

In setTimeout, i is exactly the same variable as i outside setTimeout.So if the value of i on the outside changes, so does the value of i on the inside.

The function passed to setTimeout runs after the for loop.Once executed, the i value is displayed at that time. After the for loop, the i value is 5, so 5 appears five times.

There are several ways to view 0, 1, 2, 3, 4 as you wish.

One way is to call another function to create a new variable.

functionprintFive(){
    for(vari=0;i<5;i++){
        setTimeout (makePrintFunction(i), i*1000);
    }
}

function makePrintFunction(value) {
    return function() {
        console.log(value);
    }
}

printFive();

jsfiddle

Each time makePrintValue is invoked, a new variable called value is generated and a function using that variable is returned.Therefore, if the i value changes, the value value does not change.

Another way is to use bind.

functionprintFive(){
    for(vari=0;i<5;i++){
        setTimeout (printValue.bind(null, i), i*1000);
    }
}

function printValue(value) {
    console.log(value);
}

printFive();

jsfiddle

bind is a method that creates a new function by passing arguments in advance without running a function.The value passed at that point will be kept, so if the value of i changes, the value already passed will not be affected.

Incidentally, in this case, you can call bind() directly to console.log:

functionprintFive(){
    for(vari=0;i<5;i++){
        setTimeout(console.log.bind(null,i),i*1000);
    }
}

printFive();


2022-09-30 20:29

It's been a while, but if you want to use js, I think you should be able to use recursive properly, so I will paste a sample code using recursive.
At some point, there is only one setTimeout running at the same time, so it's easy to stop.

<html>
<script>
( function printFive (loop, now) {
  if(!now)now=0;
  if(loop<now)return true;
  setTimeout(function(){
    now++;
    console.log(now);
    This(loop, now);
  }.bind(printFive), 1000);
})(5)
</script>
</html>


2022-09-30 20:29

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.