45

Can any body throw me some arguments for using inline functions against passing predefined function name to some handler.

I.e. which is better:

(function() {
  setTimeout(function() { /*some code here*/ }, 5);
})();

versus

(function() {
  function invokeMe() {
    /*code*/
  }
  setTimeout(invokeMe, 5);
})();


Strange question, but we are almost fighting in the team about this.

informatik01
  • 16,038
  • 10
  • 74
  • 104
glaz666
  • 8,707
  • 19
  • 56
  • 75
  • 8
    Nit-picking (and yet not): Both of those are inline functions, and neither is more predefined than the other. The only difference is that one of them is unnamed, the other one is named. It's a *significant* difference, though. (Good question, btw.) – T.J. Crowder Mar 29 '10 at 15:52
  • 1
    I would not use the term "inline" for unnamed functions. Inlining means actually "replacing a function call site with the body of the called function". This is pretty important. – neoexpert Feb 19 '20 at 11:10
  • 1
    @neoexpert Yeah that's weird, I don't know why his comment got so many upvotes. When I see "inline" I think of "compiling/interpreting the code to be as if the function didn't actually exist, and its code were copied to wherever it's called", coming from c++ world: http://www.cplusplus.com/articles/2LywvCM9/ https://en.wikipedia.org/wiki/Inline_function – Andrew Jul 01 '20 at 15:12
  • Okay so according to [here](https://www.geeksforgeeks.org/what-is-the-inline-function-in-javascript/) they're using "inlining" as an anonymous function (function expression) that is then assigned to a variable. Strange. – Andrew Jul 01 '20 at 15:16

13 Answers13

57

Named functions

There is some serious misuse of terminology in the question and answers on this page. There is nothing about whether or not a function is inline (a function expression) that says you cannot name it.

This is using a function expression:

setTimeout(function doSomethingLater() { alert('In a named function.'); }, 5);

and this is using a function statement:

function doSomethingLater() { alert('In a named function.'); }
setTimeout(doSomethingLater, 5);

Both examples are using named functions and both get the same benefits when it comes to debugging and profiling tools!

If the name is specified (the text after "function" but before the parenthesis) then it is a named function regardless of whether it is inline or declared separately. If the name is not specified then it is "anonymous".

Note: T.J. points out that IE mishandles named function expressions in a non-trivial way (See: http://kangax.github.com/nfe/#jscript-bugs) and this is important to note, I'm simply trying to make a point about the terminology.

Which should you use?

In response to your direct question, you should use a named function statement if the function could ever be used from any other place in your code. If the function is being used in exactly one place and has no relevance anywhere else then I would use a function expression unless it is prohibitively long or otherwise feels out of place (for style reasons). If you use an inline function expression then it is often useful to name it anyway for the purposes of debugging or code clarity.

Memory leaks

Whether you name your function, use a function statement, or use a function expression has little impact on the memory leak issue. Let me try to explain what causes these leaks. Take a look at this code:

(function outerFunction() {
    var A = 'some variable';

   doStuff();
})();

In the code above, when "outerFunction" finishes "A" goes out of scope and can be garbage collected, freeing that memory.

What if we add a function in there?

(function outerFunction() {
    var A = 'some variable';

   setTimeout(function(){ alert('I have access to A whether I use it or not'); }, 5);
})();

In this code (above) the function expression we are passing to setTimeout has a reference to "A" (through the magic of closure) and even after "outerFunction" finishes "A" will remain in memory until the timeout is triggered and the function is dereferenced.

What if we pass that function to something other than setTimeout?

(function outerFunction() {
    var A = 'some variable';

   doStuff(function(){ alert('I have access to A whether I use it or not'); });
})();

function doStuff(fn) {
    someElement.onclick = fn;
}

Now the function expression we are passing to "doStuff" has access to "A" and even after "outerFunction" finishes "A" will remain in memory for as long as there is a reference to the function we passed into doStuff. In this case, we are creating a reference to that function (as an event handler) and therefore "A" will remain in memory until that event handler is cleared. (e.g. someone calls someElement.onclick = null)

Now look at what happens when we use a function statement:

(function outerFunction() {
    var A = 'some variable';

    function myFunction() { alert('I have also have access to A'); };
    doStuff(myFunction);
})();

The same problem! "myFunction" will be cleaned up only if "doStuff" does not hold a reference to it and "A" will only be cleaned up when "myFunction" is cleaned up. It does not matter whether we used a statement or an expression; what matters is if a reference to that function is created in "doStuff"!

Prestaul
  • 83,552
  • 10
  • 84
  • 84
  • 1
    Can you suggest how to void this memory leak issue? – th1rdey3 Apr 03 '15 at 06:05
  • 2
    @th1rdey3, once you are aware of how scope is managed in javascript it becomes easier to avoid. The key is: **Keep functions small and create your vars with the lowest visibility possible.** This means: don't create globals, a function should only do one thing, and if a variable is only needed inside a function, var it inside that function. That's it. – Prestaul May 19 '15 at 17:36
  • 1
    I never thought of closures as memory leaks. They can be quite useful if you're aware of them. – kamoroso94 May 12 '17 at 09:51
11

There is one significant difference between the two: The latter one has a name.

I like to help my tools help me, and so I mostly avoid anonymous functions as my tools can't give me meaningful information about them (for instance, in a call stack list in a debugger, etc.). So I'd go with the

(function(){
  function invokeMe() {
    /*code*/
  }
  setTimeout(invokeMe, 5);
})();

...form in general. Rules are meant to be broken, though, not slavishly bowed to. :-)

Note that according to the specification, there's a third alternative: You can have an inline function that also has a name:

(function(){
  setTimeout(function invokeMe(){ /*some code here*/ }, 5);
})();

The problem, though, is that every version so far of the JavaScript interpreter from Microsoft ("JScript"), including (astonishingly) the one in IE9, handles that named function expression incorrectly and creates two completely distinct functions at different times. (Proof, try it in IE9 or earlier and also in just about any other browser.) IE gets it wrong in two ways: 1. It creates two separate function objects, and 2. As a consequence of one of those, it "bleeds" the name symbol into the enclosing scope of the expression (in clear violation of Section 13 of the specification). Details here: Double take

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • @Mark: Thanks. Yours isn't objective? Seems like it is to me. – T.J. Crowder Mar 29 '10 at 16:55
  • @TJ The reuse is, but that's pretty obvious. At what point the abundance of names becomes pollution would be subjective, as well as any readability argument. It's hard to argue with more details in the stack trace. – Mark Mar 29 '10 at 16:58
  • +1 for this "Rules are meant to be broken, though, not slavishly bowed to" – plodder Mar 29 '10 at 21:50
  • There seems to be a misunderstanding of "named functions". Whether a function is inline (a function expression) or not (a function statement) does not affect whether or not it can be named. – Prestaul Jan 06 '12 at 23:08
  • For example, setTimeout(function myFunc() {}, 5) uses a named function even though it is an inline function expression and not a function statement. – Prestaul Jan 07 '12 at 00:05
  • @Prestaul: The choices the OP gave were an anonymous function expression vs. a named declaration. But yes, I should have explained more thoroughly. The JS engine in IE has a big bug in it: It can handle a function expression, and a named function declaration, but it fails to handle a *named function expression* correctly, getting it wrong in a couple of non-trivial ways. Purely an IE bug, but of course IE is a big target for JavaScript stuff. Updated the answer to offer the third option, but with the caveat; details: *Double take*](http://blog.niftysnippets.org/2010/09/double-take.html). – T.J. Crowder Jan 07 '12 at 00:25
  • Thanks for updating the post; you can have my vote now. :) IE's mishandling is shameful and I can't wait for the day that it is finally dead. Great summary of the issues here: http://kangax.github.com/nfe/#jscript-bugs – Prestaul Jan 07 '12 at 00:25
  • @Prestaul: Cheers. I was shocked to see it still in IE9. They did so much to improve JScript in IE9 that I had actually assumed they fixed this until I tested it. As you say, shameful. (And yes, it was from kangax that I first learned of this!) – T.J. Crowder Jan 07 '12 at 00:26
  • @Prestaul: Safari used to crash if you tried to create an inline named function. – Ruan Mendes Jan 07 '12 at 02:01
5

IMO, declaring a function will be useful only if you intend to re-use it later, in some other way.

I personally use function expressions (first way) for setTimeout handlers.

However you might want to know the differences between function declarations and function expressions, I recommend you the following article:

Nick DeVore
  • 9,748
  • 3
  • 39
  • 41
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • Naming a function is also the best way to avoid memory leaks. – Egor Pavlikhin Mar 31 '10 at 03:03
  • 1
    @HeavyWave: What you said needs clarification. It's true that functions that create closures are more prone to memory leaks (if you're not careful) and even if not causing a memory leak, they use more memory than they need (because you don't really usually need all the variables in the closure). However, naming a function does not mean you're avoiding the closure. Using a global named function does. But who wants write a serious js app with a bunch of global functions? It's OK for web page enhancement. In that case, though, memory is not much of a concern. – Ruan Mendes Apr 02 '10 at 15:27
  • @Juan Mendes, you are totally right. I should have clarified what I meant. Of course, simply naming a function does not guarantee there will be no leaks. I just wanted to point out that abuse of anonymous functions can lead to serious memory leakage issues, which can be crucial for web applications. – Egor Pavlikhin Apr 02 '10 at 16:10
  • 1
    @Egor, there is absolutely nothing about anonymous functions (unnamed function expressions) that will lead to more memory leaks than named function statements. Those "leaks" are caused by closures that never leave scope and will or will not happen based on where the function is declared and the way the function is used, not the type of function you use. – Prestaul Jan 06 '12 at 23:04
  • @Juan, all functions create closures! What matters is whether or not the references to those functions go out of scope properly allowing those closures to be garbage collected and that has little to do with whether you use an expression or not. – Prestaul Jan 07 '12 at 00:09
  • @Prestaul: I disagree: global functions do not create closures, there is no outer scope, except the global scope, which is always available. Also, there's no need for an inner function inside of a function without args or local vars to create a closure (thought that would be a pretty useless inner function). Can you point me to a resource that proves that all functions create closures? What you are saying is akin to saying that all local variables need to be gc'd, whereas we all know that if they don't get passed to anything else they are just popped from the stack immediately, no need to gc – Ruan Mendes Jan 07 '12 at 00:34
  • @Juan, there is no such thing as "global scope" in javascript. At least not in the way that other languages have a global scope accessible from any place in code. The way "global scope" is accomplished in javascript is through closure, which is really a "scope chain". See: http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/ – Prestaul Jan 07 '12 at 00:44
  • @Juan, here is a quote: "Myth 3. Closures only apply to inner functions - Admittedly closures created by outer functions are not interesting because the [[scope]] property only references the global scope, which is universally visible in any case. Nevertheless its important to note that the closure creation process is identical for every function, and every function creates a closure." – Prestaul Jan 07 '12 at 00:46
  • @Prestaul: Thanks for the link. I definitely see your point. I'm aware that the global scope is the first scope in the scope chain. However, that same comment mentions that the closure created by the outer function (global) is not interesting. Therefore in my head, it's not useful to call that a closure since it's not how we use closures in JS. But following the letter of the law, you are more than correct! – Ruan Mendes Jan 07 '12 at 02:00
  • Link failed when I tried - same article can be found at http://kangax.github.com/nfe/ – beldaz Jan 13 '12 at 04:57
  • It helps with step debuggers. – Erik Reppen Apr 02 '14 at 21:18
3

I suggest a full duel between opposing team members to settle such arguments.

More seriously, in the end it just doesn't matter. The first form (non-named functions) tends to get unwieldy with larger functions, but isn't a big deal at all with small (1-2 line) functions. The second form is similarly harmless.

Any argument against either style is pure bikeshedding, imo.

jsight
  • 27,819
  • 25
  • 107
  • 140
  • 2
    +1 for combining a duel, a good answer and bike shed :) That's also how we got general approval here: by limiting inline function to a few lines. – Danny T. Mar 29 '10 at 15:47
  • +1 for the "full duel" comment. -1 for the bikeshedding comment. There is actually a very significant (read: non-trivial) difference between the two forms, even without reuse. – T.J. Crowder Mar 29 '10 at 15:48
  • 1
    @TJ Crowder - Sure, there are significant differences. My assumption was that the differences weren't really relevant to their debate (ie, both forms function similarly well in the case they are discussing, and some devs are just arguing based on style (even if they say otherwise)). But you're right "Any argument" is an exhaggeration. :) – jsight Mar 30 '10 at 13:38
  • Thanks for the bikeshedding link, somehow had not seen that before. – Brian Moeskau Mar 31 '10 at 03:08
2

An inline function avoids namespace pollution and predefined functions have higher reuse. I think you could make cases where each is appropriate.

Mark
  • 9,966
  • 7
  • 37
  • 39
  • In his example, there is basically *no* namespace pollution in either case. He has the whole thing wrapped in a scoping function, thereby creating a well-defined, contained namespace for the named function. No global is created. – T.J. Crowder Mar 29 '10 at 15:49
  • @T.J. True, but taking his example literally, there is nothing to debug in a call stack either and no information needed from the tools. ;) – Mark Mar 29 '10 at 16:29
  • We have no idea what complex logic is going to be where `/*code*/` is! :-) It may well call a function which calls another function which calls (etc., etc.), and he may well need to debug that. (Or it may just set the document title to "Foo!" which seems unlikely to need debugging.) – T.J. Crowder Mar 29 '10 at 16:32
  • @TJ: I know. :) I was more just trying to point out there are assumption made in all the answers. One being the code in `/*code*/` is non-trivial, and one that there is more enclosed in the scoping function than included in the example. – Mark Mar 29 '10 at 16:39
  • Ennh, *okay*. :-) But I will just point out that in the one case he did actually say (effectively) "There's code here." But still, as you say, assumptions. – T.J. Crowder Mar 29 '10 at 16:43
2

The predefined named functions can reduce the JavaScript callback hell issue, which is mentioned at http://callbackhell.com/

Alireza Fattahi
  • 42,517
  • 14
  • 123
  • 173
1

Can't we all just get along?

(function(){
  setTimeout( (function InvokeMe(){ /*some code here*/ }), 5);
})();

Only one thing really matters, IMO and that's ease of debug. A lot of step tracers won't be able to tell you anything about the func other than the fact that it was anonymous and had args but you can still define inline with a name by putting the definition in parens to force evaluation. For very simple or obvious breaking funcs, I suppose it's not a big deal but to me it's like semis. I really don't care what the other guy does if it doesn't cause pain but I try to always name my funcs because it's not hard and it can be an advantage.

Erik Reppen
  • 4,605
  • 1
  • 22
  • 26
1

I think that the only difference in a code like that is that with the second piece of code you can re-call the same function (sometimes with "timer functions" it's useful):

(function(){
  function invokeMe() {
    if(..) setTimeout(invokeMe, 5);
  }
  setTimeout(invokeMe, 5);
})();
mck89
  • 18,918
  • 16
  • 89
  • 106
  • 1
    @Pointy: True -- at a *serious* performance cost in nearly all implementations (we're talking orders of magnitude here), and not in the new "strict" mode. – T.J. Crowder Mar 29 '10 at 15:53
  • @Pointy: Yeah, I was really shocked when I learned about the performance aspect. – T.J. Crowder Mar 29 '10 at 16:33
  • @TJ I'm guessing you've seen the stuff about IE w.r.t. named functions used as rvalues http://yura.thinkweb2.com/named-function-expressions/ still that's a really good article – Pointy Mar 29 '10 at 16:36
  • @Pointy: LOL, oh yes, I know kangax from our mutual involvement in Prototype. In fact, that very article is referenced in the article on my blog I linked to in my answer. ;-) And it's not just IE, at the time he wrote that article, lots of implementations had issues. – T.J. Crowder Mar 29 '10 at 16:44
1

I know, that this is an old question, but to me there is an even more important difference than the ones already mentioned. hoisting Every function has to be created and therefore reserves some space in memory and eventually has to be GC later.

Named functions get hoisted to the beginning of the surrounding function, and are therefore created on every function call, wether they get used or not. Anonymous functions get created only if the code that defines them is executed.

//an example where you wold prefer to use an anonymous function.
//you can assign this (anonymous) function to a variable, so you get your "name" back.
function someFn(){
    if(condition){
        //the variable declaration has been hoisted, 
        //but the function is created at this point, and only if necessary.
        var process = function(value){/* */};
        switch(condition2){
            case 1: process(valueFor1); break;
            case 2: process(valueFor2); break;
            /* ... */
        }
    }
}

function someFn(){
    var process;
    if(condition){
        process = function(value){ /* A */ }
    }else{
        process = function(value){ /* B */ }
    }

    //beware, depending on your code, "process" may be undefined or not a function
    process(someValue);
}


//an example where you would prefer (/ utilize) the hoisting.
function someFn(){
    /* some code */
    while(condition){
        //some might want to keep the function definition near the code where it is used,
        //but unlike an anonymous function or a lambda-expression this process-function 
        //is created only once per function-call, not once per iteration.
        function process(value, index){ /* ... */ }
        /* ... */
        process(value, index)
    }
}

so, as a rule of thumb:

  • inside a loop there should be no anonymous function or lambda-expression

  • if you need the function only inside of a (rarely true) condition you should prefer anonymous functions over named ones, since they are only created when needed

  • if you know your buisness (JavaScript), you know when to ignore this advice

Thomas
  • 3,513
  • 1
  • 13
  • 10
0

There are no technical reasons to prefer one version over the other. For me is usually depends on two things:

  1. I want to resuse the passed callback in another context. In this case I define the function standalone and pass the reference.
  2. The callback is larger than ~10 lines of code and the function expects additional arguments after the callback. In this case it is hard to reconstruct, which values are actually passed to the function.

Example:

setTimeout(function() { // I need to scroll to see the other arguments

  // many lines of code

}, 0); // <- where does this '0' belong to?
Fabian Jakobs
  • 28,815
  • 8
  • 42
  • 39
0

In the example provided, the declaration and use of the function are so close that I think the only difference is readability. I prefer the second example.

Peter O.
  • 32,158
  • 14
  • 82
  • 96
lincolnk
  • 11,218
  • 4
  • 40
  • 61
0

I prefer to use named functions. Named functions show by name on all debuggers (air, firebug, IE).

Example:

Notice that you can also have inline named functions like

{
    method: function obj_method(){}
}

This way, when you look at the stack trace, you'll see function obj_method instead of anonymous.

Were you asking about when to inline a function rather than declare it? When it makes sense in the code. If you need it from two different places, it can't be inline. Sometimes inline make the code easier to read, sometimes harder.

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
  • @Juan: That named function expression (`method: function obj_method(){}`) doesn't work in most JavaScript implementations (including IE's JScript). It *should* work, arguably, but it doesn't. For more, see Juriy Zaytsev's article on NFEs: http://yura.thinkweb2.com/named-function-expressions/ (This link is actually in one of the other answers, and also in a comment on *another* answer.) – T.J. Crowder Mar 29 '10 at 22:46
  • @TJ I read the part about Function names in debuggers. That article explains that there are some quirks, it doesn't say that inline named functions don't work in IE. Most of the quirks can be worked around by making sure you never have two functions with the same name under the same scope. So if you have a block that will decide which function to return just name them accordingly, like addEventIE and addEventStandard and you'll be fine. The article actually says: "What it all boils down to is the fact that named function expressions is the only way to get a truly robust stack inspection." – Ruan Mendes Apr 02 '10 at 15:21
0

I tend towards named functions as well. Anonymous function refs are quick, but should only be used for simple stuff. My rule of thumb is that if the function is more than 2 lines of code, it probably belongs in it's own definition.

This is complicated by most example code making use of Anonymous functions. But the samples are usually very simplistic. The method falls apart as things get more complicated. I've seen function refs nested in function refs as the developer realized that more callbacks were needed in subsequent steps. Instead of this tree based logic, I prefer the organization of isolated functions.

And usually end up happy that I can reuse one of the functions I define later.

One important use of an Anonymous Function is when you need to pass scoped data into your function call, but then I usually just wrap my function into the anonymous function.

Named functions are also absolutely necessary if you ever get into Test Driven Development.

Ray Wadkins
  • 876
  • 1
  • 7
  • 16