Introduction
JavaScript allows developers to define functions within other functions, a technique known as nested functions. Nested functions can be useful in a variety of situations, including organizing code into logical blocks, improving the readability of large functions, and creating private methods that are only accessible within the containing function.
In this article, we will explore the basics of nested functions in JavaScript, including their syntax, how they differ from traditional functions, and how to use them effectively in your code.
Using nested functions in JavaScript
In JavaScript, a function can be defined inside another function. Such functions are called nested functions or inner functions. Nested functions have access to the variables and parameters of the outer function, as well as to the global variables and functions. They can be used to organize and structure your code, and to avoid naming conflicts.
Parent and child functions
We can have nested functions where we have a parent function - the outer function - and a child function - inner function - where the functions Here is an example of a nested function in JavaScript where we add one to the argument of the outer function and the result is added to the argument of the inner function.
function outerFunction(x) {
let y = x + 1;
function innerFunction(z) {
let w = z + y;
return w;
}
return innerFunction;
}
let result = outerFunction(1)(2);
console.log(result);
Output
4
In this example, the outer function outerFunction()
takes a single argument x
and defines a local variable y
. The outer function also defines an inner function innerFunction()
, which takes a single argument z
and defines a local variable w
. The inner function returns the value of w
.
The outer function returns the inner function as its result. This means that the inner function is a closure, which is a function that retains the access to the variables and parameters of the outer function even after the outer function has completed its execution.
To invoke the inner function, you need to call the outer function first, and then call the inner function as a property of the outer function's result. This is known as method chaining.
In the example above, we call the outer function with the argument 1
, and then call the inner function as a property of the outer function's result, with the argument 2
. The inner function calculates the value of w
as 2 + (1 + 1) = 4
, and returns the result.
Same-level functions
We can have multiple functions within a specific JavaScript environment or global scope level, and we might need to call one of such function inside another function. To illustrate this, we can create three functions - add
, divide
and stat
- and include the add
and divide
within the stat
function even though, they are all within the same global scope.
function add(a, b) {
return a + b;
}
function divide(a, b) {
return a / b;
}
function stat(a, b) {
let adx = add(a, b);
let dex = divide(a, b);
return (adx * dex) ** b;
}
console.log(stat(3, 5));
Output
2548.0396799999994
In this code, the add
and divide
functions are nested within the stat
function. This means that they are only available within the scope of the stat
function and cannot be called from outside of it. Though, the functions are all within the same-level, we were able to have nested functions by calling them within a function.
Inner anonymous function
Another approach we can see with nested functions in JavaScript is using anonymous functions within a function. The anonymous function will serve as the inner function within the outer function. To give more understanding, let’s illustrate an outer function - outer()
- that takes an argument a
, and within this function we have an anonymous function that takes a
function outer(a) {
return function (b) {
return a / b;
};
}
console.log(outer(3)(5));
Output
0.6
This code demonstrates the use of a nested function, where the inner anonymous function is defined and returned by the outer outer
function. The inner function has access to the variables in the outer function, in this case, the a
variable. This is known as a closure.
How nesting affects scope?
Functions defined at the top level of your code have global scope, whereas functions defined within another function have local scope. Let's check this example:
var migrating = true;
var fly = function(num) {
var sound = "Flying";
function wingFlapper() {
console.log(sound)
}
for (var i = 0; i < num; i++) {
wingFlapper();
}
};
function quack(num) {
var sound = "Quack";
var quacker = function() {
console.log(sound)
};
for (var i = 0; i < num; i++) {
quacker();
}
}
if(migrating) {
quack(4);
fly(4)
}
Let's visualize this as an image to understand the scope impact:
Here everything defined at the top level of the code has global scope. So fly
and quack
are both global variables. But remember fly
is defined only after the var fly = function(num)
function expression is evaluated.
wingFlapper
is defined by a function declaration in the fly
function. So it's scope is the entire function and it's defined throughout the entire fly
function body.
quacker
is defined by a function expression in the function quack
. So its scope is the entire quack
function but it's defined only after the function expression is evaluated until the end of the function body.
Notice that the rules for when you can refer to a function are the same within a function as they are at the top level. That is, within a function, if you define a nested function with a declaration
, that nested function is defined everywhere within the body of the function. On the other hand, if you create a nested function using a function expression
, then that nested function is defined only after the function expression is evaluated.
Summary
Nested functions can be useful in several situations. For example, you can use them to create utility functions that are only needed within a specific context. You can also use them to encapsulate complex logic and hide it from the rest of the code.
Keep in mind that nested functions can have a negative impact on the performance of your code because they create a new scope and add overhead to the function calls. You should use them judiciously and only when necessary.
Nested functions can help you organize and structure your code, and can provide a powerful way to create closures and encapsulate complex logic.
References
Functions - JavaScript | MDN (mozilla.org)
Anonymous function - Wikipedia
Closures - JavaScript | MDN (mozilla.org)