typeof eval("(function F(){})")

  • Thread starter Dr J R Stockton
  • Start date
D

Dr J R Stockton

The expression typeof eval("(function F(){return 3})") gives
"function" in Firefox and Chrome (and probably in Opera and Safari); but
in IE8 it gives "undefined".

What do I need to do to get the same in IE8 as in the others, i.e. for
eval to return an actual executable function, which would return 3 ?
 
G

Garrett Smith

Dr said:
The expression typeof eval("(function F(){return 3})") gives
"function" in Firefox and Chrome (and probably in Opera and Safari); but
in IE8 it gives "undefined".

Yes it does, unfortunately.
What do I need to do to get the same in IE8 as in the others, i.e. for
eval to return an actual executable function, which would return 3 ?

var f = eval("(function(){ return 3; })||0;");
var f2 = new Function("return 3;");

In ES3, the eval function uses containing scope. The Function
constructor results in a function that has global scope.
 
R

Ry Nohryb

The expression   typeof eval("(function F(){return 3})")    gives
"function" in Firefox and Chrome (and probably in Opera and Safari); but
in IE8 it gives "undefined".

Have you tried with:

txt= "function F(){return 3}";
eval("(function () { return "+ txt+ "})()");

¿?
 
R

Ry Nohryb

Have you tried with:

txt= "function F(){return 3}";
eval("(function () { return "+ txt+ "})()");

¿?

Or with:

eval("(function () { function F () { return 3; }; return F; })()");

¿?
 
L

Lasse Reichstein Nielsen

williamc said:
Question: why does 'function F(){return 3}' need the parentheses around
it to eval to 'function' in the non-IE implementations?

Because the string passed to eval is parsed as a Program, which makes
"function F(){return 3}" be evaluated as a function declaration. The
result of the eval call is the value of the last evaluated
ExpressionStatement's expression - and since there are none, the
result is undefined.

If you add the parentheses, then "(function F(){return 3})" is parsed
as a StatementExpression containing a parenthesized
FunctionExpression.

/L
 
G

Garrett Smith

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 ".
 
G

Garrett Smith

Lasse said:
[...]
If you add the parentheses, then "(function F(){return 3})" is parsed
as a StatementExpression containing a parenthesized
FunctionExpression.

s/StatementExpression/ExpressionStatement
 
D

Dr J R Stockton

In comp.lang.javascript message <[email protected]
rlyn.invalid>, Fri, 7 May 2010 22:04:33, Dr J R Stockton
The expression typeof eval("(function F(){return 3})") gives
"function" in Firefox and Chrome (and probably in Opera and Safari); but
in IE8 it gives "undefined".

What do I need to do to get the same in IE8 as in the others, i.e. for
eval to return an actual executable function, which would return 3 ?

typeof eval("T=function F(){return 3}")
 
G

Garrett Smith

williamc said:
Ok. So if I'm understanding correctly, running the eval as above is very
similar to using a function expression like...

No. When eval is called with a string argument, an execution context is
entered using the what is known as the "calling context's" scope and
`this` value. If eval was called in global context, then the `this`
value and variable object is the global object.

I suggest reading "entering an exectution context" and "Variable
Instantiation" from ECMA-262.
F = function() { return 3 } ;
alert(F()); // 3

but I'm still not entirely clear about the effect of the parentheses.
If I have code like the following...

c(); // 'c' - c is available *here* as it was created
// with a function declaration...

Yes. The function declaration was interpreted when the execution context
was entered.
try {
d();
} catch (ex) {
alert(ex.name); // 'ReferenceError' - d is not available here...
}

Identifier `d` is not available yet. It gets created in a call to eval,
and the call to `eval` has not been reached.
var foo = typeof eval("function d() { alert('d'); }"); // inside eval
[^^^^|^^^^^] [^^^^^^^^^eval context^^^^^^^^]
calling ctx

when the interpreter first enters the execution context, it sees "var
foo" and adds that to the VO.

After all variable declarations and function declarations have been
processed, statements are evaluated, as they appear in source order.

Inside this call to eval, the string value is found and parsed as a
Program, and so a new execution context is entered then. The scope and
`this` value of the calling context is passed in. The string argument is
parsed, a FunctionDeclaration is found from that and added to the scope,
the call completes normally and returns undefined.
var bar = typeof eval("(function e() { alert('e'); })");
// as in the original example, with parends
alert(foo); // 'undefined

As to be expected and explained by Stephen Weiss.
alert(bar); // 'function'

Yes, because in the second call to eval, an ExpressionStatement was
found, evaluated, and resulting value returned to the calling context,
where it is used in a typeof operation.
c(); // 'c'
d(); // 'd' - function d is now available...

// the eval seemed to act basically the same as a function expression
// would have. Overwrite d with an identical function

In a way, yes. The call to eval code is an expression; the code *inside*
that call may be a FunctionDeclaration.

A call to eval cannot modify the calling context before it has been called.

function a(){
var a = 10;
eval("a = 11");
function b(){}
}

The interpreter does two passses. In the first pass, `a` and `b` are
added to the VO. `a` gets value undefined, `b` the value of the
function. IN the second pass, `a` is assigned value 10, then eval is
called, then in that eval call, a new execution context is entered, but
using the calling context's scope (and `this` value). In that eval
context, `a` is resolved and assigned the value `10`.
d = function() { alert('d'); };
d(); // same result

// but function e is not available...

Nor should it be. I explained this previously where I wrote:

| 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.
try {
e();
} catch (ex) {
alert(ex.name); // 'ReferenceError'
}

That is the expected outcome.
 
G

Garrett Smith

Garrett said:
[...]

The interpreter does two passses. In the first pass, `a` and `b` are
added to the VO. `a` gets value undefined, `b` the value of the
function. IN the second pass, `a` is assigned value 10, then eval is
called, then in that eval call, a new execution context is entered, but
using the calling context's scope (and `this` value). In that eval
context, `a` is resolved and assigned the value `10`.
Correction:
" In that eval context, `a` is resolved and assigned the value `11`."
 
R

Ry Nohryb

In comp.lang.javascript message <[email protected]
rlyn.invalid>, Fri, 7 May 2010 22:04:33, Dr J R Stockton



typeof eval("T=function F(){return 3}")

Well. But avoid using named function expressions in IEs:

typeof eval("var T= function () { return 3 }")
 
V

VK

typeof eval("T=function F(){return 3}")

var T = new Function("return 3;");

or say with named arguments:

var T = new Function("arg1", "arg2", "return arg1 + arg2;");

Universally uniformly supported since Netscape 2.x
 
V

VK

So, instead of...

eval("function x() { alert('x is available!'); }");
x();

you have...

var x = new Function("alert('x is available!');");
x();

Are those near equivalents?

Pretty much, though the 2nd is definitely preferred over the 1st one:
the rule is to use for a particular task the language tool provided
for that exact task, use custom tools only if that tool implementation
is broken - which is not the case of any kind for Function
constructor.

As a small yet important difference to remember is that Function
constructor implements deferred parsing: the code is actually parsed
on the first function call, not on function instantiation. This way:
eval("function x() { !@#$%^& }");
will throw syntax error right away, while:
x = new Function("!@#$%^&");
will be fine until you try for the first time:
x();
 
R

Ry Nohryb

[snipped]

My reply...

Garrett's reply to that...
No. When eval is called with a string argument, an execution context is
entered using the what is known as the "calling context's" scope and
`this` value. If eval was called in global context, then the `this`
value and variable object is the global object.

Thanks, I'll read the reference material you mentioned.

What if I had said 'running the eval as above is very similar to using
the the function constructor at that point in the code'?

I've read in various sources that the function constructor is in effect
like a call to Eval, but have never really thought about it before,
since I've literally never used eval.

So, instead of...

eval("function x() { alert('x is available!'); }");
x();

you have...

var x = new Function("alert('x is available!');");
x();

Are those near equivalents?

Yes and no. Yes because both return a function. No because the
function that eval returns has the current scope in scope, unlike the
one that Function() returns:

var a= 27;
(function () {
var a= 10;
var f1= Function("return a;");
var f2= eval("(function () { return a })");
alert ([f1(), f2()]);
})()

--> [27, 10]
 
G

Garrett Smith

williamc said:
[snipped]

My reply...
Garrett's reply to that...
No. When eval is called with a string argument, an execution context is
entered using the what is known as the "calling context's" scope and
`this` value. If eval was called in global context, then the `this`
value and variable object is the global object.

Thanks, I'll read the reference material you mentioned.

What if I had said 'running the eval as above is very similar to using
the the function constructor at that point in the code'?

It sounds like you're guessing.

To understand the language on how it is interpreted, put yourself in
first person to think as the interpreter. Can you explain, for example:

function x(){
var a;
eval("a = 19");
}

x();

When x is called, what happens? Review the section "entering an
execution context".

function y(){
var a;
var f = new Function("a = 19");
return f;
}

var bb = y();

What happens here? What happens when bb is called?
I've read in various sources that the function constructor is in effect
like a call to Eval, but have never really thought about it before,
since I've literally never used eval.

Function constructor is like eval in that evaluates a string of code as
SourceElements.
So, instead of...

eval("function x() { alert('x is available!'); }");
x();

you have...

var x = new Function("alert('x is available!');");
x();

Are those near equivalents?
No.

The first has a call to eval. The evaluated string has the expected
outcome as explained in detail to you previously, adding an `x` property
to the VO.

The second is a call to the Function constructor which creates and new
function whose scope is global.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top