Fis
Fis

Reputation: 807

Javascript - function / closure variable scope - where is the variable defined?

I am working on my worker remote method invocation and class instantiation and I was doing some eval research with closures. I came with the code bellow which I really like and I'll use it, but don't really understand why it works and how it works. Actually, I don't understand where the 'a' variable is stored and also where the name of it is stored as I can access it inside the function or by calling evals. Also, I would like to know what is its life cycle and when it will get destroyed. Is it a hack of JS engine or is it valid usage? I tested with IE10, IE11, Chrome, FF, Opera, Safari, Safari mobile... it works everywhere. I am so curious.

https://jsfiddle.net/bykwm1h3/2/

function scope(params) {
    if (params) {
        a = params;
    } else {
        console.log(a);   
    }   
}

function evalInScope(code) {
    eval.call(this, code)
}

// define variable - where is it defined?? definitely in the scope of the function as it is accessible there but, who really holds its instance?
evalInScope.call(scope, "var a;");

// setup variable values
scope([1,2,3]);

// print it out
evalInScope.call(scope, "console.log(a)");

// or print it out
scope();

Upvotes: 1

Views: 72

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074148

Your a is a global variable, because you're doing an indirect eval. When you do indirect eval, the code you pass eval is evaluated at global scope. var at global scope creates global variables.

The more canonical way to do indirect eval is either to use a variable:

var x = eval;
x("code here");

or use the comma operator:

(0, eval)("code here");

Direct eval (eval("code here")) evaluates the code you pass it within the scope in which the eval call appears.

And yes: This business of direct vs. indirect eval is confusing, surprising, and not consistent with how other functions work. It wasn't designed, it grew and was codified. :-)

If your goal was to evaluate the code within the scope function, that's not what that code does. To do that, you'd use eval within scope:

function scope(code) {
    eval(code);
}

You can prove to yourself a is a global by seeing if it ended up as a property on the global object, which we can access via the window global on browsers:

function scope(params) {
    if (params) {
        a = params;
    } else {
        console.log(a);   
    }   
}

function evalInScope(code) {
    eval.call(this, code)
}

console.log("a in window?", "a" in window); // false
evalInScope.call(scope, "var a;");
console.log("a in window?", "a" in window); // true

Upvotes: 4

Related Questions