Nested functions (or inner functions) in JavaScript are a useful feature. They are functions inside another function. Learn how to create a nested function. How variable scopes, closures & lexical scopes work. Also learn to create multi-level nested function, passing parameters to them etc
Table of Contents
Nested Function
A nested function is a function inside another function
We can create the nested function in the same way we create the normal JavaScript function, But inside another function
In the following example, we create the logToConsole function inside the addNum function. We can invoke logToConsole just like any other function, but only inside the addNum function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | function addNum(a,b) { //nested function function logToConsole(message) { console.log(message); } let result=a+b; //invoking the nested function logToConsole("result is "+result) } addNum(1,2) ***output *** result is 3 |
Variable Scope in Nested Function
The nested functions have their own scope. But they also have access to the parent functions scope. Hence you need to remember two important points.
- A nested function is private to containing function
- A nested function can access the containing function’s scope
Nested function is private to containing function
Only the containing function can access the nested function. We cannot access it anywhere outside the function. This is because the inner function is defined in the scope of the outer function (or containing function).
In the example below, we try to access the logToConsole from the outside of the addNum function. But It will result in an error.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | function addNum(a,b) { function print(message) { console.log(message); } let result=a+b; logToConsole("result is "+result) } logToConsole("10") //Uncaught ReferenceError: logToConsole is not defined |
Nested function can access the containing functions scope
The nested function can access all variables, functions & arguments defined in the containing function. This ability where the inner function can access the parent function scope is known as Lexical scope.
In the example, we do not pass any value to logToConsole. Inside the nested function, we can access both arguments of the containing function i.e. a & b, and also the result variable.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | function addNum(a,b) { function logToConsole() { console.log(`result of %d + %d is %d`,a ,b,result); } let result=a+b; logToConsole() } addNum(1,2) |
Returning a Nested Function
The container function can return the nested function. In the following example, the makeCounter initializes the count property and returns the increment function. We store the inner function in the counter property
Whenever we invoke the counter it will increment the count and return the result. What makes it interesting here is that the increment function can still access the count property of the makeCounter, although the makeCounter function finished its execution. This works because of a JavaScript feature known as Closure
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | function makeCounter() { let count = 0; increment = function () { return ++count; }; return increment; } //storing the inner or nested function counter = makeCounter() //Invoking the nested function. This will increment the count property by 1 console.log(counter()); console.log(counter()); console.log(counter()); *** Result *** 1 2 3 |
Closure
The count property is local to the makeCounter function. The increment function can access it because it is nested inside the makeCounter function.
In this line of code, we invoke the makeCounter, which initializes the count to 0 and returns the increment function.
1 2 3 | counter = makeCounter() |
Usually, we expect JavaScript to clean up the memory when the function returns. But in the example above, we return the inner function which needs to access the count property of makeCounter function. Cleaning up the memory will make the count property inaccessible to the inner function.
In such cases, JavaScript keeps the memory alive and attaches it to the inner function. This is called closure. The JavaScript keeps this in memory as long as someone has reference to the increment function.
Hence, when we invoke the increment function using the counter variable, it will increment the count property. Because the count property is not destroyed and still in memory.
1 2 3 4 5 | console.log(counter()); console.log(counter()); console.log(counter()); |
In this example, we invoke makeCounter twice. Each call to makeCounter will get its own memory and count property. Because of this each of returned nested functions gets its own copy of the count property. Hence they do not interfere with each other.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | function makeCounter() { let count = 0; increment = function () { return ++count; }; return increment; } counter1= makeCounter() counter2= makeCounter() console.log(counter1()); //1 console.log(counter1()); //2 console.log(counter1()); //3 console.log(counter2()); //1 console.log(counter2()); //2 console.log(counter2()); //3 |
Returning a new object with a nested function
In the following example, the function does not contain a nested function but returns an object, which contains a function. Technically the function inside the object is also a nested function. It can also access the properties of its parent function i.e. makeCounter
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | function makeCounter(counterName) { let count = 0; let counterObj = { name: counterName, increment: function () { ++count; console.log("name %s count %d",this.name,count) return count } } return counterObj } counter1=makeCounter("Counter1") counter2=makeCounter("Counter2") counter1.increment() counter2.increment() counter2.increment() counter1.increment() counter1.increment() counter2.increment() |
Parameters in nested function
You can also pass arguments to inner function. In the following example, outerfunc returns the innerFunc. Both accepts a parameters
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function outerfunc(a) { innerFunc = function (b) { console.log("a %d b %d",a,b) }; return innerFunc; } //Get Inner Function InnerFunc=outerfunc(5); //Invoke it InnerFunc(3); //Invoke invoke inner Function directly outerfunc(10)(2); |
The code InnerFunc=outerfunc(5) returns the inner function. You can invoke it as nnerFunc(3)
Another way to invoke the inner function is using the outerfunc(10)(2)
Mulitple levels of Nesting
We can also create multiple levels of nested functions in JavaScript. The following code is a 3 level nested function.
outerFunccontains a functionInnerFunc, which itself contains a functioninnermostFunc.outerFunccan invokeinnerFunc. But cannot invokeinnermostFuncinnerFunccan access the properties & methods ofouterFuncinnermostFunccan accessinnerFunc. It can also access theouterFunc
The Important point to note here is that innermostFunc can access the outerFunc. This is because the scopes are recursive. The innermostFunc contains the scope of the innerFunc. The innerFunc contains the scope of outerFunc. This is called scope chaining.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function outerFunc(a) { innerFunc = function (b) { innermostFunc = function (c) { console.log("a %d b %d c %d", a, b, c) } return innermostFunc; }; return innerFunc; } //Invoke it outerFunc(10)(2)(7); //a 10 b 2 c 7 //Another way a = outerFunc(10) b = a(2) c = b(7) //a 10 b 2 c 7 |
Name conflicts
We run into name conflict when two functions define the same variable. For Example in the following example innerFunc defines variable a. Hence it will hide the a variable of the outerfunc. Hence the innermostFunc will also see the variable from the innerFunc because that is its immediate parent.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | function outerfunc(a) { innerFunc = function (b) { a=5 innermostFunc = function (c) { console.log("a %d b %d c %d", a, b, c) } return innermostFunc; }; return innerFunc; } //Invoke it outerfunc(10)(2)(7); //a 5 b 2 c 7 //Another way a = outerfunc(10) b = a(2) c = b(7) //a 5 b 2 c 7 |



In no-2 program’s line no 5 the function name should be “logToConsole” as declared in the previous program