williamc said:
Question: why does 'function F(){return 3}' need the parentheses around
it to eval to 'function' in the non-IE implementations?
It doesn't. In fact, eval('function F(){return 3}') works as specified
in Spidermonkey and in Webkit's JS engine. The different behavior you
are seeing in IE is caused by JScript interpreting an expression and
returning that value.
A FunctionDeclaration is not an Expression; it cannot return a value.
Understanding the behavior you may be seeing requires an understanding
of how the language is designed to be interpreted and how JScript
deviates from that.
When the (one) argument to eval is a string value, it is parsed as a
Program. In ES3, eval uses the calling context's scope. What that means
is that when eval is called, it can access and can create variables
using the scope chain from where it was called. An example of that.
var a = 9;
function testEval(){
var a;
// When eval is called, calling context's scope is used.
eval('a = 11');
return a;
}
alert(testEval(), a)
When `testEval` is called, a VO is created and `a` added to it with
value `undefined`. When the `eval` function is called, that VO is used
and so expression 'a = 11' resolves `a` on that VO.
The string starting with "function F(){return 3}" could be parsed only
as a FunctionDeclaration. This is because an ExpressionStatement cannot
begin with "function ".
When a FunctionDeclaration is parsed, as is the case with your example
code, it is added as a property to the VO (Variable Object).
and so the code:
eval("function F(){return 3}");
- should create a property of the calling context's scope.
And indeed it does:
eval("function F(){return 3}");
F();
FunctionDeclarations are not Expressions and so eval completes normally
and returns undefined, as can be expected.
A FunctionDeclaration is not a Statement and as such, needs not be
followed by a terminating semicolon, thus:
eval("function F(){return 3}alert(F())");
- runs, but:-
eval("(function F(){return 3})alert(F())");
- is a SyntaxError because every statements must be terminated by a
semicolon or a line terminator, in some cases, but ASI discussions
getting off topic.
What you are seeing in Microsoft JScript is that the Token is evaluated
as both an Expression and a FunctionDeclaration. When JScript sees:
eval("function F(){return 3}");
It sees a FunctionExpression. According to MS-ES3, JScript parses both a
FunctionDeclaration and a FunctionExpression. The identifier F is added
to scope. This is a well-known JScript bug.
An ExpressionStatement cannot start with the function keyword because
that might make it ambiguous with a FunctionDeclaration.
Thus:
eval("function(){return 3}");
- should result in SyntaxError.
JScript does not throw a SyntaxError there because it allows f
When the Program starts with an expression, such as:
eval("(function F(){return 3})");
- the eval function parses the Grouping Operator is an expression and
returns the value, the function F.
There is one more significant difference here: The optional identifier
in a FunctionExpression does not affect the enclosing scope. This means
that with:
eval("(function F(){return 3})");
The identifier `F` is not added to enclosing scope.
Unlike a FunctionDeclaration, which is, as was demonstrated above. Again:
eval("function F(){return 3}");
A FunctionDeclaration is parssed and identifier `F` is added to
enclosing scope with the value of that function.
So again, a FunctionDeclaration is not an Expression. And an
ExpressionStatement cannot begin with "function ".