Shirgill Farhan Ansari Shirgill Farhan Ansari - 3 months ago 9
Javascript Question

Functions created with the Function constructor are always created in the global scope

From the MDN description of Function:


Note: Functions created with the Function constructor do not create
closures to their creation contexts; they always are created in the
global scope. When running them, they will only be able to access
their own local variables and global ones, not the ones from the scope
in which the Function constructor was called. This is different from
using eval with code for a function expression.


I understand,

var y = 10;
var tester;
function test(){
var x = 5;

tester = new Function("a", "b", "alert(y);");
tester(5, 10);
}
test(); // alerts 10


Replacing the
tester = new Function("a", "b", "alert(y);");
with
tester = new Function("a", "b", "alert(x);");
, I will get

// ReferenceError: x is not defined


But couldn't understand the author's line-


...they always are created in the global scope.


I mean how is the
new Function("a", "b", "alert(y);");
nested within the
test
fn is in
global scope
?

In fact, accessing it from outside the
test
fn will simply result in


Uncought TypeError:tester is not a function


Please elucidate.

Answer

In your example, "created in the global scope" means that tester will not have closure over x from test:

function test(){
  var x = 5;
  tester = new Function("a", "b", "alert(x);"); // this will not show x
  tester(5, 10);
}

When you new up a Function, it does not automatically capture the current scope like declaring one would. If you were to simply declare and return a function, it will have closure:

function test(){
  var x = 5;
  tester = function (a, b) {
    alert(x); // this will show x
  };
  tester(5, 10);
}

This is the trade-off you make for having dynamically compiled functions. You can have closure if you write the function in ahead of time or you can have a dynamic body but lose closure over the surrounding scope(s).

This caveat doesn't usually matter, but consider the (slightly contrived) case where you build a function body as a string, then pass it to a function constructor to actually be evaluated:

function addOne(x) {
  return compile("return " + x + " + 1");
}

function addTwo(x) {
  return compile("return " + x + " + 2");
}

function compile(str) {
  return new Function(str);
}

Because the function is instantiated by compile, any closure would grab str rather than x. Since compile does not close over any other function, things get a bit weird and the function returned by compile will always hold a closure-reference to str (which could be awful for garbage collection).

Instead, to simplify all of this, the spec just makes a blanket rule that new Function does not have any closure.

Comments