Functions and function scope

TODO: add section on this and method binding --Maian 02:45, 19 September 2005 (PDT)


Since this page is getting large very fast, I'm planning on creating a category devoted to Core JavaScript 1.5 Reference:Functions that will have the following subcategories:

* ways to create functions (links to Core_JavaScript_1.5_Reference:Objects:Function, Core_JavaScript_1.5_Reference:Statements:function, and Core_JavaScript_1.5_Reference:Operators:Special_Operators:function_Operator)
** Core JavaScript 1.5 Reference:Functions:Function constructor vs. function declaration vs. function expression

Because of name conflicts and for consistency, moving objects page to Core_JavaScript_1.5_Reference:Global Objects, top-level functions to Core_JavaScript_1.5_Reference:Global Functions, and top-level properties to Core_JavaScript_1.5_Reference:Global Properties.

Any comments? Name suggestions?

--Maian 07:04, 8 September 2005 (PDT)

: Yes, this sounds fine. Thanks for your help! --Nickolay 12:11, 8 September 2005 (PDT)

About "Function constructor vs. function declaration vs. function expression" section

I'm going to just criticize it a bit, don't have time to write something better right now --Nickolay 04:00, 6 September 2005 (PDT)

1) The 4th example would better be

var multiply = function f(x, y) { return x * y; }

- to demonstrate the real difference between the function expression and function declaration, which is that function declaration affects the current scope, while function expression does not: alerting f after the above statement would cause a reference error.

Renamed the function name to func_name but feel free to change it to something more sensible. I already mentioned that func names can only be used in the function's body, but I'll clarify that section a bit. --Maian 06:57, 6 September 2005 (PDT)

We should also mention recursion here.

Agreed, though I wonder how many examples we'll need for that. --Maian 06:57, 6 September 2005 (PDT)

2) "static" isn't really a good term, I think, although I admit I don't have a better idea.

Well, I just changed it to "function's name can't be changed". --Maian 06:57, 6 September 2005 (PDT)

3) This doesn't work for me when executed in global scope, rv:1.8b4 Gecko/20050828. Haven't read the spec on it yet:

foo(); function foo() {alert('FOO!');}
That's odd. It works on Fx/1.06, IE/6SP2, Opera/8.02. In any case, it's part of the ECMAScript spec. Lemme dig it up... It says func declarations are parsed first before running the rest of the script. --Maian 06:57, 6 September 2005 (PDT)
Whoops, that was just the JS Shell I was using. It actually works fine. --Nickolay 08:28, 6 September 2005 (PDT)

4) I don't like using the "precompiled" term, when you actually mean "parsed only once".

I used "compiled" here for consistency, since the "general" subsection right under "description" also uses that term (and who knows where else): "declared functions are compiled". --Maian 06:57, 6 September 2005 (PDT)

5) I think the second list should be unordered, I first thought each item of that list was going to explain the corresponding declaration from the first list.

Agreed. --Maian 06:57, 6 September 2005 (PDT)

6) Should this section, the section about closures, etc. be separated from the main article? That would make it easier to link to them from other articles, and it would also make this article smaller and easier to scan.

Yes, but I don't know where it should be put. TBH, I don't think any of these function specifics should even be under the Function object. It should be put in a totally new chapter. Same thing applies for the method binding section. --Maian 06:57, 6 September 2005 (PDT)
I think we can just put it outside of the JS reference hierarchy. E.g. "Nested functions and closures in JavaScript" --Nickolay 08:28, 6 September 2005 (PDT)
Well, can you tell me what the scope of the reference is? I'm under the impression that anything important about JavaScript that concerns developers should be put there. --Maian 00:29, 7 September 2005 (PDT)
I didn't write it, so I don't know. I think this info is welcome as part of the reference. What I meant was - we are free to name the pages whatever we want. My original intention was to call it "Nested functions and closures in JavaScript", but maybe Core JavaScript Reference:Nested functions and closures would be more consistent with the rest of docs. Dria likes consistency. --Nickolay 02:34, 7 September 2005 (PDT)
But where would it appear on the reference TOC? Well in any case, I'll leave the reorganization to you. --Maian 02:37, 7 September 2005 (PDT)
Now that I think about it, there needs to be section devoted to functions in general. There are three places discussing functions: this section, function statement, and function operator. --Maian 03:45, 7 September 2005 (PDT)


Conditionally defining a function

Functions can be conditionally defined using function expressions or the Function constructor. {{ mediawiki.external('quote') }} In the following script, the zero function is never defined and cannot be invoked, because 'if (0)' evaluates to false:

if (0)
   function zero() {
      document.writeln("This is zero.");

If the script is changed so that the condition becomes 'if (1)', function zero is defined.

Note: Although this looks like a function declaration, this is actually a function expression since it is nested within another statement. See differences between function declarations and function expressions. {{ mediawiki.external('/quote') }} Actually, the conditional function may have ambiguous behavior here.

The syntax - if(0) expression - is perfectly legal. An expression cannot start with the function keyword because that might make it ambigous with a FunctionDeclaration.

12.4 Expression Statement

   ExpressionStatement :
       [lookahead ∉ {{, function}] Expression ;
   Note that an ExpressionStatement cannot start with an opening curly brace because that might make it ambiguous with a Block. Also, an ExpressionStatement cannot start with the function keyword because that might make it ambiguous with a FunctionDeclaration.

-- Garrett

About "Specifying an event handler with a Function object"

This section should be moved down to the example section and revised. The JS reference should be as DOM-independent as possible (with the exception of alert and window). Also, I think the "onEvent" naming has lost favor and should simply be called the "event" event, e.g. "onFocus" => "focus", to comply with the naming conventions set by DOM2 Events. --Maian 07:11, 6 September 2005 (PDT)

Name conflicts

Where I noticed name conflicts myself was when I was calling another function within a for (i=0;etc..) loop, and the function in question was using a for (i=0;etc..) loop, and the 2 i's were in conflict with each other. Simple fix was to rename the 2nd i to j instead. Perhaps this is a good example of the hidden pitfalls with using identically named functions?

new Function() vs function(){}

The article states that the code given to new Function() is parsed every time the function is executed and that function constructors should be avoided because of that. I did a few benchmarks (on Firefox, Spider Monkey 4.0 I think and Windows XP) and could not reproduce that.

Consider the following:

function test1() {
  var f = function(){ return 1; };
  for (var i = 0; i < 10000; i++) f();
function test2() {
  var f = new Function("return 1;");
  for (var i = 0; i < 10000; i++) f();
function test3() {
  for (var i = 0; i < 10000; i++) eval("1");
function test4() {
  for (var i = 0; i < 10000; i++) (new Function("return 1;"))();

test1() is running very fast as expected. test3() and test4() are crawling along, no surprise here either. But test2() which, according to the article, should have a similar speed as test4() or at least test3(), runs on my machine actually as fast as test1(). For me this looks as if code passed in a function constructor is actually parsed once, when the function object is created and not each time it is executed. Which would make sense to me.

Don't get me wrong, I don't want to promote the use of new Function instead of function(){} here. I just want to point out that, if you absolutely have to parse a string as code, new Function() is still a lot more efficient than eval().

Maybe the information in the article is from an old version of Spider Monkey? --Ps 08:05, 12 May 2007 (PDT)

Efficiency considerations: Closures considered harmful???

Because of this inefficiency, avoid closures whenever possible, i.e. avoid nesting functions whenever possible. For example, consider the following example:

function assignOnclick(element) {
  element.onclick = function() { = 'blue';

This can be rewritten to avoid the closure. However, the anonymous inner function would need to be named and would no longer be private to assignOnclick:

function assignOnclick(element) {
   element.onclick = element_onclick;

function element_onclick() { = 'blue';

Please explain to me how the second example is in any way different than the first - except that it pollutes the global namespace with a function that is called by name exactly never.

Of course you create a new function object each time you create a closure. and of course the local variables the closure uses stay as long as the function object exists. But those are the basic rules of object creation and in no way specific to functions. And like every other object, the function object will be garbage collected once it is no longer referenced. I don't see how you can create memory leaks here if you don't try very hard.

IMO, the second example is efficiency-wise even worse than the first. If the object in element happens to be unloaded, the event hander in the first example would be unloaded as well, like it should - but in the second example, it would still stick around, because it is referenced by the unused global property element_onclick.

function outside(x) {
  function inside(y) {
     return x + y;
  return inside;
result = outside(3)(5); // returns 8

In this case, the closure of inside is stored in result. Since result is in the global scope, the closure will remain until the script is unloaded (in a browser, this would happen when the page containing the script is closed).

In this example, clearly the result of calling inside() is stored in result, not the function itself. inside() is returned by outside(3), executed with y = 5 and immediately thrown away. In no way it can hog memory here.

I think this whole section is just plain wrong and should be rewritten. It doesn't look for me as if the author had a very deep understanding of closures, I'm sorry. Please comment.--Ps 05:31, 17 May 2007 (PDT)

Yep, the text in this section is partially incorrect. However, I believe there's a closure-related bug in IE, and in general you have to be careful when using closures. Suppose you have
function init() {
  var bigObject = createBigObject();
  var result = bigObject.doSomething();
  gElement.onclick = function() {

Here you keep bigObject alive until the anonymous closure is gone, even though it only needs the result variable from the init() function scope.

Also, at least in earlier versions it was much easier to leak stuff in Gecko this way. For chrome JS leaking examples see this. --Nickolay 06:58, 17 May 2007 (PDT)

I agree with the criticism (came here to write the same thing myself) and have now deleted that section, replacing it with a warning that closures keep objects alive in a sometimes less obvious way. The closure-related bug in IE you were thinking of is probably the problem that old IE has trouble breaking cycles between the DOM and Javascript objects. I don't think it has anything to do with closures per se, although that's an easy way of generating them. -- Ole Laursen, 9 Sep 2011


Section "Conditionally defining a function"

AFAICS, conditionally defining a function throws an error in at least ES5 strict, possibly non-strict (at least soon), too, see Bug 609832 and Bug 585536. The section "Conditionally defining a function" should be updated to reflect those changes. I added a short sentence, but IMO this should be a big red box. --fbender 05 May 2012