Javascript Function() Constructor Does Not Create A Closure

Posted April 28, 2010 at 8:38 AM by Ben Nadel

Tags: Javascript / DHTML

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.




Reader Comments

Apr 28, 2010 at 8:54 AM // reply »
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.


Apr 28, 2010 at 8:57 AM // reply »
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


Apr 28, 2010 at 8:58 AM // reply »
11,238 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 :(


Apr 28, 2010 at 8:59 AM // reply »
11,238 Comments

@Brian,

Ha ha, got ourselves a little comment-tag going on :)


Apr 28, 2010 at 9:05 AM // reply »
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.


Apr 28, 2010 at 9:15 AM // reply »
11,238 Comments

@Kathryn,

Yeah, probably. Most of me expected this behavior; but, part of me hoped it didn't work that way.


Apr 28, 2010 at 11:50 AM // reply »
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.


Apr 28, 2010 at 12:13 PM // reply »
11,238 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.


May 5, 2010 at 5:36 AM // reply »
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


May 5, 2010 at 9:49 AM // reply »
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.


May 6, 2010 at 3:56 AM // reply »
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.


May 6, 2010 at 9:41 PM // reply »
11,238 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 :)


May 6, 2010 at 9:48 PM // reply »
8 Comments

@Ben,

You can eval huge chunks of logic.

http://blog.sproutcore.com/post/225219087/faster-loading-through-eval

I just started listening to The Dev Show on 5by5.tv ( http://5by5.tv/devshow ) and they talked about that link above on their first show.

Surprising results, to say the least. Check it out. :)


May 6, 2010 at 9:54 PM // reply »
11,238 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 :)



Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
May 17, 2013 at 7:42 PM
HashKeyCopier - An AngularJS Utility Class For Merging Cached And Live Data
Ben - thanks so much for posting these Angular articles and findings, they've been a huge help towards learning one of the more 'complex' JavaScript frameworks out there (IMO). I have been using Angu ... read »
May 16, 2013 at 5:01 PM
UPDATE: Parsing CSV Data Files In ColdFusion With csvToArray()
Your code was the closest thing I've found to obtaining some direction for converting ISO fields to values that CF can translate properly. Thank you for posting! ... read »
May 15, 2013 at 10:37 PM
Very Simple Pusher And ColdFusion Powered Chat
hi id making plz easy ... read »
May 15, 2013 at 6:07 PM
Making SOAP Web Service Requests With ColdFusion And CFHTTP
Ben, you once again saved my bacon at work. Thank you, thank you, thank you! ... read »
May 15, 2013 at 4:15 PM
What If All User Interface (UI) Data Came In Reports?
@Josh, Thanks! @Ben, I definitely recommend the David West book "Object Thinking" I've been quoting from. It goes deeply into the philosophy and history of OO programming. His breadth ... read »
May 15, 2013 at 11:36 AM
Ask Ben: Print Part Of A Web Page With jQuery
I found this helpfull when you need to keep (refresh) the original parent page after closing the iframe child print dialog (Hoping you're not using a form at this time so it won't submit again): On ... read »
May 14, 2013 at 7:13 PM
What If All User Interface (UI) Data Came In Reports?
@Jonah, If there's any books you'd recommend on the subject of domain modelling, I'd love to hear it. I just downloaded the free PDF of "Domain Driven Design Quickly". Figured I'd give it ... read »
May 14, 2013 at 6:57 PM
The UX Of Prototyping: Low-Fidelity Is The New High-Fidelity
@Phillip, I'm not sure I follow what you mean? Are you saying that you looked at the list of widgets provided by the jQuery UI and let that be your style guide? ... read »
InVision App - Prototyping Made Beautiful With Prototyping Tools