user3026691
user3026691

Reputation: 497

Trouble Eval'ing Function Definitions (...in JavaScript)

I'm trying to build a simple REPL by evaling user-supplied strings. It seems to work for the most part, except for inputs like "function f() {...}", which have no effect on which functions are visible in future evals. After playing around with it for a bit, I can only conclude that I don't understand eval at all. Here's a short snippet demonstrating some mysterious behaviors:

var xeval = eval;

function silly() {}

eval("function good() {}");

function baffleMe() {
    eval("alsoGood = function() {}");
    eval("function notSoGood() {}");
    xeval("function hope() {}");
    xeval("function crushedHope() { silly(); }");
}

baffleMe();

good();         // Okay.
alsoGood();     // Okay.
notSoGood();    // ReferenceError: notSoGood is not defined
hope();         // Why does this even work?
crushedHope();  // ReferenceError: silly is not defined

Could anyone explain these results, please? (Reproducible in both the latest Chrome and Firefox)

[EDIT]

To clarify, the last call fails only when the code is executed in the Javascript console or tools like JSFiddle, but not when embedded in a script tag. The comments on accepted answer contain the explanation for this.

Upvotes: 3

Views: 52

Answers (2)

Konstantin Dinev
Konstantin Dinev

Reputation: 34895

I will try to explain:

Good is evaluated on the global scope:

good();         // Okay.

Alsogood has no var definition, thus is being defined on the global scope:

alsoGood();     // Okay.

NotSoGood is defined inside the function scope, thus does not exist on the global scope:

notSoGood();    // ReferenceError: notSoGood is not defined

Hope is evaluated by a closure reference of eval on the global scope, thus it's evaluated on the global scope:

hope();         // Why does this even work?

CrushedHope is the same as hope, but silly should be defined in this case:

crushedHope();  // ReferenceError: silly is not defined

As mentioned in the comments below, silly is undefined in the question when using JSFiddle and when the code is wrapped with window.onload.

Upvotes: 1

Scimonster
Scimonster

Reputation: 33399

This is a feature of ECMAScript5. To quote MDN:

If you use the eval function indirectly, by invoking it via a reference other than eval, as of ECMAScript 5 it works at global scope rather than local scope; this means, for instance, that function declarations create global functions, and that the code being evaluated doesn't have access to local variables within the scope where it's being called.

So directly calling eval() creates the function in local scope. (Using the a=something method automatically creates a global.) But when you indirectly call it by xeval() it gets evaluated globally.

Your final result of silly being undefined is dependent on the scope you're evaluating in. If you're in the console, it seems to have a different scope. If you create a test HTML page, it works properly.

Upvotes: 1

Related Questions