1

We are given a code snippet in run time along with a name of a variable used in code. We want to evaluate the given code and log the value of the variable.

Example:

suppose our code is var foo = "Blah"; and the name of the var is foo.

eval('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);');

yields Blah.

yet

new Function('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);')();

yields undefined.

Is there a way to make get this to work with new Function?

Barmar
  • 596,455
  • 48
  • 393
  • 495
Oded
  • 43
  • 3
  • 1
    `new Function('var foo = "Blah"; let varName = "foo"; console.log(eval(varName));')();` works, but this isn't really a good practice. – marco-a Sep 09 '20 at 17:46
  • If you're constructing the code dynamically, why can't you just write `console.log(foo)` instead of having to use `varName`? – Barmar Sep 09 '20 at 18:01
  • Indeed it works! Confused, where is this value stored while the Function is evaluated? (new to JS for quite some time ;) ). – Oded Sep 09 '20 at 18:04
  • @Barmar: the example I wrote is a bit simplistic. The name of the var "foo" is given in evaluation time. For context, am working with the blockly API, which provides the name of variables created by blockly user, yet does not seem to provide their value. See:https://developers.google.com/blockly/reference/js/Blockly.VariableMap – Oded Sep 09 '20 at 18:12
  • Do you have access to the `VariableMap` object, so you can use `getVariable()`? – Barmar Sep 09 '20 at 18:14
  • Variable Map holds the type, name and id of variable yet not the value. Will continue investigating the API route on a different thread. – Oded Sep 09 '20 at 18:54

3 Answers3

1

With new Function, you're creating a new function. The code that is executed looks something like:

function someFunction() {
  var foo = "Blah"; let varName = "foo"; console.log(this); console.log(this[varName]);
}
someFunction();

There, foo is in local scope of the someFunction. It's not global, so variables declared with var inside the function don't get put onto the global object.

In contrast, eval runs on the top level. Your eval code that is executed looks something like:

var foo = "Blah"; let varName = "foo"; console.log(this[varName]);

which is all on the top level, so the foo variable that was declared gets put onto the global object, the this.

CertainPerformance
  • 260,466
  • 31
  • 181
  • 209
  • Thanks, but still confused. Is there a way to retrieve the value of 'foo' from this 'local scope' of this 'someFunction'? – Oded Sep 09 '20 at 17:57
  • 1
    Not dynamically, unfortunately, or at least not in any sane manner. See https://stackoverflow.com/questions/5187530/variable-variables-in-javascript. If you have to do something like that, use an object instead. The standalone variables exist in the LexicalEnvironment of that function block. – CertainPerformance Sep 09 '20 at 18:04
  • With pleasure sir! A bit of topic: the community in Stack Overflow is amazing. Thanks for taking the time to answer this. Still a bit confused regarding the place where these local variables are stored. Expected this to point to the object that stores them. – Oded Sep 11 '20 at 16:39
  • The local variables are "stored" in the Lexical Environment of a block, which holds records of variable names and the values they point to. This object is not directly visible to JS; the only way to look into it dynamically is with (silly and bad) uses of `eval` or `new Function`. (A reasonable script should never depend on its variable names in order to work correctly.) `this`, on the other hand, refers to the current calling context, see https://stackoverflow.com/questions/3127429/how-does-the-this-keyword-work – CertainPerformance Sep 11 '20 at 17:20
0

Substitute the variable name into the function definition directly, rather than using this.

let varName = 'foo';
new Function(`var ${varName} = "Blah"; console.log(${varName});`)();
Barmar
  • 596,455
  • 48
  • 393
  • 495
0

Everything here is about Scope. Global Scope and Block Scope.

Global Scope

Variables declared Globally (outside any function) have Global Scope.

var bikeName = "Honda";

// code here can use bikeName

function myFunction() {
  // code here can also use bikeName
}

and

    var greeter = "hey hi";
    
    function newFunction() {
        var hello = "hello"; //Variables declared Locally (inside a function) have Function Scope.
    }

    console.log(hello); // error: hello is not defined

Here, greeter is globally scoped because it exists outside a function while hello is function scoped. So we cannot access the variable hello outside of a function.

Block Scope

A block is a chunk of code bounded by {}. A block lives in curly braces.

   let times = 4;

   if (times > 3) {
        let hello = "say Hello instead";
        console.log(hello);// "say Hello instead"
    }
   console.log(hello) // hello is not defined

You should read about them. Things will get clear

Hence in your case:

new Function('var foo = "Blah"; let varName = "foo"; console.log(this[varName]);')();

Everything inside function has function scope and will not be available global!

Dolly
  • 1,081
  • 4
  • 24