28

I have an opinion (which I am sure will be shared by some) that passing anonymous functions which contain more than a few lines of code, as arguments to other functions affects readability and self-documentation drastically, to the point where I feel it would be far better for anyone likely the use the code to just declare a named function. Or at least assign that anonymous function to a variable before declaring the main function

However, many JavaScript libraries (jQuery, d3.js/NVD3.js) just to give a couple of examples, use large functions in this way.

Why is this so widely accepted in JavaScript? Is it a cultural thing, or are there advantages which I'm missing, which would make the use more preferred than declaring a named function?

10
  • 1
    It probably has a lot to do with using closures. It might also have to do with not wanting to expose the actual function to the outside world (which is why it is anonymous). Feb 26, 2016 at 18:24
  • 3
    @RobertHarvey In other words, it's a workaround for JavaScript not having public and private? Feb 26, 2016 at 18:59
  • 2
    In many places a large anonymous function reads more like a block and generally feels pretty good once you get used to it. Scoping rules even support the block feel.
    – user69767
    Feb 27, 2016 at 0:14
  • 5
    @MasonWheeler: That depends on your perspective. A Scheme or ECMAScript programmer might say that public and private are workarounds for not having proper closures. Feb 27, 2016 at 14:33
  • 1
    @JörgWMittag Hooray for Racket, the official language sponsor of XKCD 927! Feb 28, 2016 at 9:18

2 Answers 2

25

Three main reasons I can think of:

  1. Parent Scope Access
  2. Privacy
  3. Reduction of names defined in higher scopes

Parent Scope Access: Inline function definitions allow the inline code to have access to variables defined in parent scopes. This can be very useful for many things and can reduce the amount or complexity of code if done properly.

If you put the code in a function defined outside of this scope and then call the code, you would then have to pass any parent state that it wanted to access to the function.

Privacy: Code inside an inline anonymous definition is more private and cannot be called by other code.

Reduction of names defined in higher scopes: This is most important when operating in the global scope, but an inline anonymous declaration keeps from having to define a new symbol in the current scope. Since Javascript doesn't natively require the use of namespaces, it is wise to avoid defining any more global symbols than minimally required.


Editorial: It does seem to have become a cultural thing in Javascript where declaring something anonymously inline is somehow considered "better" than defining a function and calling it even when parent scope access is not used. I suspect this was initially because of the global namespace pollution problem in Javascript, then perhaps because of privacy issues. But it has now turned into somewhat of a cultural thing and you can see it expressed in lots of public bodies of code (like the ones you mention).

In languages like C++, most would probably consider it a less-than-ideal practice to have one giant function that extends across many pages/screens. Of course, C++ has namespacing built in, doesn't provide parent scope access and has privacy features so it can be motivated entirely by readability/maintainability whereas Javascript has to use the code expression to achieve privacy and parent scope access. So, JS just appears to have been motivated in a different direction and it's become somewhat a cultural thing within the language, even when the things that motivated that direction aren't needed in a specific case.

1
  • 2
    As a C++ developer recently moved to JS for a lot of my work, this answer makes a lot of sense, particularly the 'parent scope access' point - it really does have the power to greatly simplify your code. One nitpick - C++ does provide parent scope access in C++11 lambdas :) Definitely +1 though. Feb 27, 2016 at 2:26
9

Anonymous functions are used for many more purposes in JavaScript than they are in most languages.

First, they are used for namespacing and block scoping. Until recently JavaScript has lacked modules or any other kind of namespacing mechanism which has led to using anonymous functions to provide that functionality via the Module Pattern. There would be absolutely no benefit in naming these functions. At a smaller scale, due to JavaScript's lack of block scoping until recently, a similar pattern was used to mimic block scoping; most notably in the body of loops. Using a named function in this case would be actively obfuscatory.

Second, and less JavaScript specific, anonymous functions are often used with higher order functions that mimic control structures. For example, jQuery's each method. I doubt you abstract every loop body or if-branch into a function whenever it's more than a few lines long. The same logic applies in this case.

A final reason is event-based programming is common in JavaScript which tends to lead to an inadvertent continuation-passing style code. You make an AJAX call and register a callback which, when executed, will make another AJAX call and register a callback etc. If the calls were synchronous rather than asynchronous, this would just be a straight-line sequence of code in a single lexical scope. Again, I doubt you would abstract every few lines of straight-line code into a function.

There are also cultural factors and, for the reasons above among others, anonymous functions are far more common in JavaScript than many other languages and are used more comfortably/laxly than many other languages.

1
  • My own, perhaps naïve structures in C++ coding have sometimes taken principles of event-based coding and callbacks from JavaScript via std::function and lambdas. In my case, it's partially because I'm doing UI code in C++ and don't want to perform blocking operations. I'm curious if JavaScript's practices are simply useful to anyone as long as the language supports them well.
    – Katana314
    Feb 26, 2016 at 20:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.