Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Sara Dunnack
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Sara Dunnack

Javascript Function() Constructor Does Not Create A Closure

By
Published in Comments (14)

Yesterday, when I was building the basis of the jQuery Template Markup Language (JTML), I made use of Javascript's Function() constructor to dynamically generate HTML template rendering engines. I've only use the Function() constructor once or twice before so I'm not too familiar with it. I know that ordinarily, when you define a function, it creates a closure with its parent scope; but I wasn't sure what kind of bindings are generated when a function is crated with a Function() constructor call.

Testing this was rather easy - all I had to do was create two like-named variables in competing scopes. Then, I had to use the Function() constructor to define a function within the inner scope that makes reference to said variable. If the resultant function references the inner variable, a closure was created; if not - if the function references the outer variable - no closure was created.

<!DOCTYPE HTML>
<html>
<head>
	<title>Javascript Function() Context</title>
	<script type="text/javascript">

		// Define this variable in the Window scope.
		var scope = "window";


		// Run a self-contained function.
		(function(){

			// Create a locally scoped variable.
			var scope = "function";

			// Define a function that logs the current scope value.
			// If this creates a closure, it will log, "function."
			// If it does not, it will log, "window."
			var testScope = new Function(
				"console.log( scope );"
			);

			// Execute the test function.
			testScope();

		})();

	</script>
</head>
<body>
	<!-- Left blank intentionally. -->
</body>
</html>

As you can see here, I have dually defined the "scope" variable in the window context as well as in the self-contained function. The function, testScope(), is then created within the self-contained function and does nothing more than log the "closest" scope value. When I run this page, I get the following console output:

window

As you can see, the generated function found the window-scoped variable which means that its creation did not form a closure to the self-contained function. While I understand why this might happen, I think it would have been awesome if the Function() constructor created a closure to the calling context. I just think this would have been much more useful, and, in a way, might even be more consistent with how all other function declarations work in Javascript.

Want to use code from this post? Check out the license.

Reader Comments

8 Comments

I'm not sure if I've really seen functions created like that. If you tweak the interior to something like:

var testScope = function() {
console.log( scope );
};

Then it outputs 'function' instead of 'window'.

Definitely seems like something about going the new Function route breaks the inherited scope, which is odd but could be an interesting trick.

8 Comments

Posted a bit prematurely: I realize you're aware that the non-quoted syntax works fine, but guess there's likely a reason for trying to use the new Function syntax that I'm not aware of. :D

15,848 Comments

@Brian,

Yeah, most definitely. If you watch the video, I actually do just what you are saying to demonstrate the difference in lexical binding between the two function declarations. It just would have been cool :(

3 Comments

I believe the new operator takes the scope from where the object base is located, in this case the object base is "Function" and as such it is located within the window scope. ie typeof window.Function returns "function" which is why when you use function with the new operator it gives you the "scope" variable from the window scope.

8 Comments

@Ben,

I should have watched the video. I was waking up and trying to be quiet or might have otherwise. :D

Also, I decided to go reading, and on page 117 of the ECMAScript language spec I dug up (well, page 127 of the PDF but it's numbered 117), it explicitly says that when using the function constructor like this, that it receives the global scope. Seems like it'd be really nice if there were a way to use this sort of syntax but then specify to act as though it were a standard function declaration.

15,848 Comments

@Brian,

I thought you might be able to use call() or apply(), but as far as I know, that only works for "this". It doesn't actually affect the implicit scope chain.

1 Comments

In my opinion if you are using new Function your missing the power of closures. However if you really need this try function(){eval("...")}

var foo = "win";
(function(){
var foo = "fun";
(function(){eval("console.log('eval: ' + foo)")})();
(new Function("console.log('Func: ' + foo)"))();
(function(){console.log('func: ' + foo)})();
})();

gives

eval: fun
Func: win
func: fun

1 Comments

<q>I believe the new operator takes the scope from where the object base is located, in this case the object base is "Function" and as such it is located within the window scope. ie typeof window.Function returns "function" which is why when you use function with the new operator it gives you the "scope" variable from the window scope.</q>

By the same logic, eval should work as Function, but it does not.

Presumably the reason for the difference of scope resolution of eval and Function is simply due to the spec. The 262 version denotes (in section 10.2.2) that eval runs in the same context as the calling context (the SAME context, no new activation record is pushed on the stack)

(function(){
var foo = "fun";
eval("foo = 'eval';");
alert(foo); // shows eval
})();

Where as Function, when called as a function works differently (sec 15.3.2.1 step 16).

I'd just guess that it's either:

1. A botched job from having to create a standard from a complex language (possibly backwards compatability issues)
2. A "nice" way to be able to setup two different scope chains, depending on what you need. Your way of using Function above is not any different if you used eval, which would get you what you want.

1 Comments

Your function creation still creates a closure.
Right before the call to testScope(), assign a different value to the scope variable. It will still print "window" to the console.

The problem is just that the creation of the new Function uses the global variable instead of the local variable. I'm not sure why that is, but at least it still encapsulates state, which results in a closure.

15,848 Comments

@Eval,

I am not a huge fan of eval(). I like it for things like evaluation JSON (although I know people see that as faux pas these days. I am not sure that I can really get what I want out of closures either. I LOVE LOVE LOVE closures, but the problem is that I need to locally scope some variables in the calling scope for use in the compiled function and creating a closure in the traditional sense I am not sure would have solved the problem.

@Svend,

I wonder if I can stuff more things into eval() than I realized. I know you can eval a single line of Javascript; but, I wonder how well it holds up trying to eval() several lines of Javascript logic. Perhaps I'll play with that as an experiment.

@Ampersandre,

Right - I guess the problem is not so much that a closure wasn't created... more that it wasn't the closure I wanted :)

15,848 Comments

@Brian,

Awesome my man. I'll be checking that out first thing in the morning. Right now, however, I need to create a solid combination of PB&J sandwiches and TV :)

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel