3

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.

3
  • See difference between window.eval (global.eval in Node) and eval Commented Jan 13, 2016 at 15:02
  • closely related: global.eval is not able to visit variables in the lexical scope Commented Jan 13, 2016 at 15:04
  • If you're going to make a REPL, you should put the string evals in try catch statements, and if the error message is Unexpected end of input, then prompt for more code until the eval works, or returns a different error. Commented Jan 13, 2016 at 16:12

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

@user3026691 crushedHope doesn't produce the error you describe when I test it in Chrome's and Firefox's consoles. Where are you seeing this error?
@user3026691 Ah, I see the problem: if your code isn't global (e.g., wrapped inside of a (function() { ... })() IIFE, then silly isn't global. However, crushedHope is global, so it can't see the your locally-defined silly function inside the IIFE.
It does in JSFiddle and in the Javascript console... 0_o
@user3026691 You need to change your fiddle "Load Type" settings from "onLoad" to "No wrap". Defining your silly function inside of a load event listener function makes it inaccessible to the global-scope crushedHope
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.