Because no answer is specific about why the last snippet fails, and nobody seems to be warning you for the dangers of eval
:
eval
, according to MDN:
A string representing a JavaScript expression, statement, or sequence of statements. The expression can include variables and properties of existing objects.
Your string, "function foo(){console.log('foo');}()"
actually consists of 2 statements, that make no sense to the JS engine. Well, the second one doesn't:
function foo(){console.log('foo');}//function declaration, fine
;//<-- js adds implied statement terminator
()//no invocation, because no function reference, group nothing ==> does not compute, raise error
That's why you have to turn your function declaration statement into an expression, by adding an operator. Typically, this is the grouping operator: ()
(function foo(){ console.log('foo')});
The function declaration is now an expression, everything (the grouping ()
included) can be seen as a statement, unless the code that follows belongs to the code above. In this case, the invoking parentheses clearly do, so the JS engine sorts it out for you.
For clarity, some say the preferred notation is:
(function f(){}());//<-- invoking parentheses inside group
Which makes sense, because the invocation is part of the statement, after all.
If you don't like all these parentheses, any operator will do:
~function(){}();//bitwise not
+function(){}();//coerce to number
Are all equally valid. Note that they will change the possible return values of the function expression.
(function(){}());//resolves to undefined
+function(){}();//resolves to NaN, because undefined is NotANumber
How your eval
could look, then, is any of the following:
eval("(function (){console.log('foo');}());");
eval("~function (){console.log('foo');}();");
eval("!function (){console.log('foo');}();");
And so on, and so forth...
Lastly, eval
evaluates code in the global scope, so any code eval
-ed containing functions can, and likely will, polute the global namespace. Mallicious code will also have access to everything, so be weary of XSS attacks and all other JS based techniques.
Bottom line, eval
is evil, especially since all browsers now support JSON.parse
natively, and for those that don't, there still is a tried and tested JSON2.js file out there.
Using eval
in strict mode does make things slightly safer, but doesn't prevent XSS attacks at all, the code can still manipulate the DOM, for example, and reassign exposed DOM references or objects.
Google "why eval is evil" if you want to find out more.
Also check the ECMAScript specs