8

I know that eval and setTimeout can both accept a string as the (1 st) parameter, and I know that I'd better not use this. I'm just curious why is there a difference:

!function() {
    var foo = 123;
    eval("alert(foo)");
}();

!function() {
    var foo = 123;
    setTimeout("alert(foo)", 0);
}();

the first would work, and the second will give an error: foo is not defined

How are they executed behind the scene?

wong2
  • 34,358
  • 48
  • 134
  • 179

5 Answers5

6

See the reference of setTimeout on MDN.

String literals are evaluated in the global context, so local symbols in the context where setTimeout() was called will not be available when the string is evaluated as code.

In contrast, the string literal passed to eval() is executed in the context of the call to eval.

Wolfram
  • 8,044
  • 3
  • 45
  • 66
  • and the code passed to `eval` will execute in the context where `eval` is executing? – wong2 Jul 27 '12 at 09:03
  • Exactly, the string literal is evaluate "in-place" and has access to the variables defined in that context. – Wolfram Jul 27 '12 at 09:05
  • @wong2 actually it depends how you call `eval`. In modern browsers, the following eval is in global scope: http://jsfiddle.net/4p9QY/ because it's indirect eval. Here are more examples of indirect eval calls http://perfectionkills.com/global-eval-what-are-the-options/#indirect_eval_call_examples – Esailija Jul 27 '12 at 09:40
2

setTimeout's eval is additionally executed in global scope, so it's not aware of foo.

Here's reference to back it up:

String literals are evaluated in the global context, so local symbols in the context where setTimeout() was called will not be available when the string is evaluated as code.

Esailija
  • 138,174
  • 23
  • 272
  • 326
1

setTimeout takes more parameters than function reference and timeout. Anything entered past timeout will be passed to your function as a parameter.

setTimeout(myFunction(param1, param2), 0, param1, param2);
0
!function() {
    var foo = 123;
    eval("alert(foo)");
}();

When executing this code, javascript will pretend that line 3 says "alert(foo)". Foo is defined in the scope of the function.

!function() {
    var foo = 123;
    setTimeout("alert(foo)", 0);
}();

When executing this code, javascript will enter a new function; namely function() {alert(foo)}. In the scope of that 'new' function, foo is not defined.

0

As a complement to the correct answer, here is a call to eval that would give you the same behavior, and error in this cases:

!function() {
    var foo = 123;
    window.eval("alert(foo)"); // <- note the window.eval, this is important and changes the behavior of the `eval` function
}();

!function() {
    var foo = 123;
    setTimeout("alert(foo)", 0);
}();

This blog post goes in depth on the different types of eval: http://perfectionkills.com/global-eval-what-are-the-options/

fabiomcosta
  • 1,105
  • 1
  • 8
  • 10