What's going on under the hood here? Javascrip

2019-05-18 00:57发布

Can someone break down what's going on here clearly?

function timerCheck() {
    for(var i=0; i<5; i++) {
        setTimeout(function() {
            console.log("Hello" + i);
        }, 3000);
    }
}

So as some of you may know, calling this function will not work as expected. What will end up happening is that this function will get called 5 times all at once with i set to 5 each time. This will be the output after 3 seconds:

Hello5
Hello5
Hello5
Hello5
Hello5

I also understand that using the setInterval method is the right way to approach this kind of problem, but I am curious what's going on under the hood here. I really want to understand how Javascript works. Please note that I do not have a computer science background, just a self-taught coder.

3条回答
Viruses.
2楼-- · 2019-05-18 01:30

Variable scope in JavaScript is limited to functions.

In your example, the variable i is declared inside of timerCheck. This means that at the end of the loop, i will be equal to 5.

Now, adding in the call to setTimeout doesn't change the fact that i is scoped to timerCheck and that i has been modified to equal 5 by the time the code inside each setTimeout call has run.

You can create a function that "captures" the value of i so that when you call it from inside your loop you get new variable scope for the setTimeout call:

function createTimer(j) {
    setTimeout(function() {
        console.log("Hello" + j);
    }, 3000);
}

function timerCheck() {
    for(var i=0; i<5; i++) {
        createTimer(i);
    }
}

Since createTimer takes a parameter j, when you pass i from inside the for loop in timerCheck to createTimer, j is now scoped to createTimer so that each setTimeout call has its own j.

查看更多
聊天终结者
3楼-- · 2019-05-18 01:35

This might help you understand what's going on better:

function timerCheck() {
    for(var i=0; i<5; i++) {
        console.log("Hi" + i);
        setTimeout(function() {
            console.log("Hello" + i);
        }, 3000);
        console.log("Bye" + i);
    }
}

You'll see

Hi0
Bye0
Hi1
Bye1
Hi2
Bye2
Hi3
Bye3
Hi4
Bye4

Immediately printed to the console, because all five iterations of the loop finish very quickly, and then after five seconds you'll see:

Hello5
Hello5
Hello5
Hello5
Hello5

because the timeouts (which were all set at approximately the same time) all occur at once, and since the loop already finished: i == 5.

This is caused by the scope of i. The variable i has a scope of everywhere after it is declared in timerCheck(); There is no local i inside your anonymous function in setTimeout set there is no var i, and i isn't given as an argument to the function.

You can fix this easily with a closure, which will return a function that has a local copy of i:

function timerCheck() {
    for(var i=0; i<5; i++) {
        setTimeout((function(loc_i) {
            return function() {
                console.log("Hello" + loc_i);
            };
        })(i), 3000);
    }
}

Which will output:

Hello0
Hello1
Hello2
Hello3
Hello4

To understand this:

(function(loc_i) {
    return function() {
        console.log("Hello" + loc_i);
    };
})(i)

You have to know that a function can be executed immediately in Javascript. IE. (function(x){ console.log(x); })('Hi'); prints Hi to the console. So the outer function above just takes in an argument (the current value of i) and stores it into a local variable to that function called loc_i. That function immediately returns a new function that prints "Hello" + loc_i to the console. That is the function that is passed into the timeout.

I hope that all made sense, let me know if you're still unclear on something.

查看更多
Summer. ? 凉城
4楼-- · 2019-05-18 01:45

This is actually an add-on to Andrews answer

If you try to set a variable that sets the output it explains the scope also.

function test()
{
    for(var i=0; i<5; i++) {
    t = "Hello " + i + "<br/>";
    document.write(t);
        setTimeout(function() {
            document.write(t);
        }, 3000);
    }
}

as you can see the writes will be as expected but at the time the setTimeout fires the t variable will be the last set. Which will be Hello 4.

so the output will be

Hello 0
Hello 1
Hello 2
Hello 3
Hello 4

from the loop and

Hello 4
Hello 4
Hello 4
Hello 4
Hello 4

from the setTimeout

查看更多
登录 后发表回答