简体   繁体   中英

setTimeout(“fn(x)”) doesn't work correctly

I have a timer function which alerts a text 'hello, welcome' in a pop up for every 2 seconds. Also I have a function to clear the timer interval so as to stop the pop up at 10th second.

The pop up box showing is stopped when I use the clearInterval function line as

setTimeout(function() {clearInterval(x); },10000);

But the pop up box showing is not stopped when I use the settimeout function as

setTimeout("clearInterval(x);",10000);

However If I use settimeout function to display a pop up by defining the builtin function directly as setTimeout("alert('hello, welcome');",2000); // works properly setTimeout("alert('hello, welcome');",2000); // works properly

Can you please explain why the settimeout function behaves differently for the above two lines. Please find my code below.

<html>
<head>
<script type='text/javascript' >
function testclear()
{
    var x = setInterval("alert('hello, welcome');",2000);
    setTimeout(function() { clearInterval(x); },10000);

   // setTimeout("clearInterval(x);",10000);
}
</script>
</head>
<body>
    <input id='txt' onchange='testclear()' />
</body>
</html>

But the pop up box showing is not stopped when I use the settimeout function as

setTimeout("clearInterval(x);",10000);

That is because when you eval that string, the variable 'x' has not been properly captured. It will probably point to window.x (and not your local variable that holds the interval timer id).

Whereas the closure in the working example has captured the proper x .

One more reason to avoid eval .

You don't have this problem (yet) with your alert, because it does not reference any variables, but I suggest you also change it to closure ("function") form.

I do believe that when you specify a string for the first parameter of setInterval or setTimeout , it will be executed with eval at the specific time/interval. Because of that, it is run in the global scope. In your case, x is not available in the global scope...it's a local variable scoped inside of the testclear function. Passing a function as the first parameter to setInterval or setTimeout secures the scope you were originally working with (inside the testclear function).

Alternatively, yet not preferably, I believe you could do this:

setTimeout("clearInterval(" + x + ");",10000);

But note that this concatenation may be different or not possible in other situations (other method calls)

That's because x is local to the function testclear() . When you pass function to setTimeout, it will get the same scope as the one it was written in, thus x will be recognized.

When you pass string literal, it will be evaluated but the scope is lost.

It will also "work" if x will be global variable, however it's not a good practice.

Working Example Here I have customised your code and it works fine.

  1. Make x variable global.
  2. var t= setTimeout(' clearInterval(x);' ,1501); set temp variable to catch setTimeout ,it is semantics to follow.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM