Sergey Sahakyan
Sergey Sahakyan

Reputation: 739

Javascript variable capture

I faced with strange behaviour when using eval in JS.

var f = function () {
    var x = 10;

    return function () {
        eval('console.log(x);');
        window['eval']('console.log(x);');
    }
};

f()();

OUTPUT:

10
undefined:1
console.log(x);
            ^
ReferenceError: x is not defined

Why using eval explicitly captures the x but global['eval'] doesn't? And even though global['eval'] doesn't capture x, why it's unable to see after eval, which already captured x?

Upvotes: 7

Views: 1164

Answers (4)

Dan
Dan

Reputation: 10548

Your inner function does not actually capture the reference of x, and so it is never directly passed to eval.

eval usually works at the local scope and so the first call succeeds (because the local scope contains the declaration of x).

However, if you invoke eval in such a way that you don't have a direct reference to it, it will invoke itself in the global scope, which var x is not a part of, and it fails.

Just don't use eval.

Upvotes: 3

Grzesie2k
Grzesie2k

Reputation: 19

window.eval work in global scope.

var variable = 1;

(function(){
  var variable = 100,
      cmd = "++variable";
  document.write(eval(cmd)+"\n"); // increment local var 100 and output 101
  document.write(window.eval(cmd)+"\n"); // increment global var 1 and output 2
})();

Upvotes: 1

StvnBrkdll
StvnBrkdll

Reputation: 4044

window['eval'] operates at global scope, eval() operates at local scope.

From Mozilla's Javascript reference:

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.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

Upvotes: 7

guest271314
guest271314

Reputation: 1

You can use Function.prototype.bind() to pass x to returned function

var f = function () {
    var x = 10;

    function y(n) {
        eval(`console.log(${n})`);
        window["eval"](`console.log(${n})`);
    }

    return y.bind(this, x)
};

f()();

Upvotes: 2

Related Questions