Reputation: 2844
While I was expecting that this code
var a = eval("function() { return 1; }");
console.log(a());
prints '1' in the console, I get a syntax error Uncaught SyntaxError: Unexpected token (
. What am I doing wrong here?
I am working with a framework that allows to define javascript functions in the configuration, so I have no other choice but using eval.
Upvotes: 0
Views: 132
Reputation: 29086
The problem is that you have a function declaration and that requires a name. For reference, this is a function declaration
function myFunc() { console.log("executed") } //<-- declaration
myFunc(); //<-- execution
What you expect to have is an unnamed function expression
var myFunc = function() { console.log("executed") }
//expression ^------------------------------------^
myFunc(); //<-- execution
Or for a truly unnamed function that you do not assign to a variable, you can have an IIFE
// v--------- brackets surrounding expression ---------v
( function() { console.log("executed") } )()
//expression ^------------------------------------^ ^^
//execution -------------------------------------------++
However, in JavaScript a standalone statement that starts with the function
keyword will be treated as declaration and if it doesn't have a name, it is invalid.
However, you can go around that by surrounding the expression in brackets to make it acceptable for the parser.
//brackets v--------------------------v
var a = eval("( function() { return 1; } )");
// ^----------------------^ function expression
console.log(a());
Upvotes: 2
Reputation: 215029
The function
keyword is ambiguous in Javascript: it can start a function declaration (a statement), or a function literal (an expression). When function
is encountered in the statement position, the parser voluntarily prefers declaration over expression. Since eval
expects a statement, this makes your code invalid -- function name is required for declarations. You can either provide a name:
eval('function foo() {...}')
or force the parser into the expression mode
foo = eval('( function () {...} )')
in which case function
will be treated as a literal.
This is basically the same story as with {}
, which can be either a block or an object literal. Something like eval('{1:2}')
will fail for exactly the same reason (statement preferred over expression).
Upvotes: 4
Reputation: 8589
You cannot mix function declaration and function expressions this way. You have to do the full declaration or expression inside the eval()
.
eval("function a() { return 1; }");
console.log(a());
This would work, as we give the function declaration a proper name, a
, and then call the function this creates on the global scope.
eval("var a = function() { return 1; }");
console.log( a() );
This would also work, since the function expression assigning it to the variable a
is now part of what gets evaluated. And we can then call the function in it's scope.
Neither of these should actually ever be used if there's alternatives.
The most common alternative is using new Function();
.
var a = new Function( 'return 1;' );
console.log( a() );
This achieves the same end result and is slightly safer than using eval()
.
I would be surprised though if this was the only way the framework allows to define extra javascript functions. I guess that since it's in the config of something the security issues this gives are less important than if it's public code. But i would reread the docs of the framework to double check that this is the only option.
Upvotes: 1
Reputation: 508
As the comments are 100% true that a function must contain a name or has to be initialised as an anonymous function, there is a solution to your problem.
If you want to create a function by text you could use the function constructor
new Function ([arg1[, arg2[, ...argN]],] functionBody)
For more information look at https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Function
Upvotes: 1