Javascript Tutorial
Javascript Tutorial Introduction to Javascript JavaScript Code Editors & IDE JavaScript Hello World Example Javascript Syntax and Rules syntax_rules javascript_identifiers JavaScript Keywords & Reserved Words javascript_variables JavaScript Const JavaScript let vs var vs const Data Types in JavaScript JavaScript String Template Literals & String interpolation in JavaScript Tagged Templates in JavaScript String to Number in JavaScript Number Data Type in JavaScript NaN in JavaScript JavaScript Number Min & Max & Safe Values JavaScript EPSILON & Floating point precision Infinity in JavaScript JavaScript Bigint BigInt Vs Number in JavaScript Boolean Data Type in JavaScript Undefined in JavaScript Null in JavaScript Null vs Undefined in JavaScript JavaScript Operators Arithmetic Operators in JavaScript Unary plus & minus operators in JavaScript Increment & Decrement Operators in JavaScript Comparison or Relational operators in JavaScript Strict Equality (==) Loose Equality (===) in JavaScript Ternary Conditional Operator in JavaScript Logical Operators in JavaScript Bitwise Operators in JavaScript Assignment Operators in JavaScript Nullish Coalescing Operator in JavaScript Comma Operator in JavaScript Typeof JavaScript Operator Precedence in JavaScript JavaScript if, else & nested if statement Switch Statement in JavaScript While & Do While Loops in JavaScript For Loop in JavaScript Break statement in JavaScript Continue Statement in JavaScript Arrays in JavaScript Array Constructor in Javascript Sparse Array Vs Dense Array in JavaScript How to merge Arrays in JavaScript Array Methods in JavaScript Functions in JavaScript Function Parameters & Arguments in JavaScript JavaScript Default Parameters Pass by Value and Pass by Reference in Javascript Function Expression in Javascript Nested Functions in JavaScript Immediately-invoked Function Expressions (IIFE) JavaScript Callback Functions Arrow Functions in JavaScript Arguments Object In JavaScript Rest Parameters in JavaScript Objects in Javascript Create Objects in JavaScript JavaScript Object Properties Computed Property Names in JavaScript Object Literal in JavaScript Constructor Function & New Operator in JavaScript Delete Operator in JavaScript hasOwnProperty in JavaScript Using Getters and Setters in Javascript DefineProperty in JavaScript JavaScript Property Descriptors Enumerable, Writable & Configurable Object Destructuring in JavaScript Variable Scope in JavaScript Hoisting in JavaScript Lexical Scope & Closures in JavaScript This in JavaScript Global Object, Window & Globalthis in JavaScript Call function in Javascript Prototype In Javascript Prototype Inheritance in JavaScript Instanceof Operator in JavaScript Spread Operator in JavaScript

Nested Functions in in Javascript

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

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.

                            
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.

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.

                            
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.

                            
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

                             
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.

                            
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.

                            
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.

    
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

                            
                            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

    
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.

  • outerFunc contains a function InnerFunc, which itself contains a function innermostFunc.
  • outerFunc can invoke innerFunc. But cannot invoke innermostFunc
  • innerFunc can access the properties & methods of outerFunc
  • innermostFunc can access innerFunc. It can also access the outerFunc

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.

    
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.

    
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