Specifically, I’m writing in JavaScript.
Let’s say my primary function is Function A. If Function A makes several calls to Function B, but Function B is not used anywhere else, then should I just place Function B within Function A?
Is that good practice? Or should I still put Function B at the same scope as Function A?
I’m generally in favor of nested functions, especially in JavaScript.
- In JavaScript, the only way to limit a function’s visibility is by nesting it inside another function.
- The helper function is a private implementation detail. Putting it at the same scope is akin to making a class’ private functions public.
- If it turns out to be of more general use, it’s easy to move out, because you can be confident the helper is currently only used by that one function. In other words, it makes your code more cohesive.
- You can often eliminate parameters, which makes the function signature and implementation less verbose. This is not the same thing as making variables global. It’s more like using a class member in a private method.
- You can give the helper functions better, simpler names, without worrying about conflicts.
- The helper function is easier to find. Yes, there are tools that can help you. It’s still easier to just move your eyes up the screen a bit.
- Code naturally forms a sort of tree of abstraction: a few general functions at the root, branching out into several implementation details. If you use an editor with function folding/collapsing, nesting creates a hierarchy of closely-related functions at the same level of abstraction. That makes it very easy to study the code at the level you need and hide the details.
I think a lot of opposition comes from the fact that most programmers were either brought up in a C/C++/Java tradition, or were taught by someone else who was. Nested functions don’t look natural because we weren’t exposed to them much when we were learning to program. That doesn’t mean they aren’t useful.
1
You should put it at global scope, for several reasons.
-
Nesting a helper function into the caller increases the length of the caller. Function length is almost always a negative indicator; short functions are easier to understand, to memorize, to debug and to maintain.
-
If the helper function has a sensible name, reading that name is enough without needing to see the definition nearby. If you do need to see the helper definition in order to understand the caller function, then that caller is doing too much, or is working on too many levels of abstraction simultaneously.
-
Having the helper globally available allows other functions to call it if it turns it to be generally useful after all. If the helper isn’t available, you’re tempted to cut and paste it, or to forget it and reimplement it, poorly, or to make another function longer than it has to be.
-
Nesting the helper function increases the temptation to use variables from the caller’s scope without declaration, so that it becomes unclear what the inputs and outputs of the helper are. If a function doesn’t clearly state what data it operates on and what effects it has, it is usually a sign of unclear responsibilities. Declaring the helper ass a standalone function forces you to know just what it actually does.
Edit
That turned out to be a more controversial question than I thought. To clarify:
In JavaScript, big file-spanning functions often fulfill the role of classes because the language doesn’t provide any other scope-limiting mechanism. Certainly helper functions should go inside such quasi-classes, not outside them.
And the point about easier reuse presupposes that if a subroutine does become more widely used, you are willing to move it out of place altogether and put it in appropriate place, e.g. a string utility library or into your global configuration registry. If you don’t want to order your code like that, then you might as well nest the subroutine, just like you would do with a normal Method Object in a more “blocky” language.
6
I’m going to propose a third path, to place both functions within a closure. It would look like:
var functionA = (function(){
function functionB() {
// do stuff...
}
function functionA() {
// do stuff...
functionB();
// do stuff...
}
return functionA;
})();
We create the closure by wrapping the declaration of both functions in a IIFE. The return value of the IIFE is the public function, stored in a variable of the name for the function. The public function can be invoked in exactly the same way as if it were declared as a global function, ie functionA()
. Note that the return value is the function, not a call to the function, thus no parens at the end.
By wrapping the two functions up like so, functionB
is now completely private, and cannot be accessed outside of the closure, but is visible only to functionA
. It is not cluttering the global namespace, and is not cluttering the definition of functionA
.
You should not nest it, because otherwise the nested function will be re-created every time you call the outer function.
Defining function B within function A gives function B access to A’s internal variables.
So, a function B defined within a function A gives the impression (or at least the possiblity) that B is using or altering A’s local variables. While defining B outside of A makes it clear that B doesn’t.
Therefore, for the clarity of the code, I would define B within A only if B needs to access local variables of A. If B has a clear purpose that is independent of A, I would definitely define it outside of A.
Since function B isn’t used anywhere else you might as well just make it an inside funtion within function A because that’s the only reason why it exists.
1