Learn Closure in JavaScript with examples in < 16 mins
Tags: javascript, webdev, beginners, programming
Published: 2022-11-21 11:02:39

There is a popular programming term `closure`, that JavaScript developers should know. Unfortunately, most developers struggle to get their heads around this concept. 

In this article, I will explain `Closure` in clear terms using simple-to-understand examples. 

To dive into `Closure`, it is essential we understand the following concepts:
- Scope
- Lexical Environment
- Functions returning Functions

Let's get started 

## Scope
Consider the analogy below:

- In our homes, there are items that are **accessible by all **members of the household. For instance, the remote control of the TV set.
- However, there are some personal or specific items that are **only accessible to you**, and you can restrict anyone from using those items. An example is your personal toothbrush or your mobile phone.

The above is essentially how `scope` works in JavaScript.

> `Scope` is "access". It permits a developer to restrict access to certain variables in specific areas.

When we define a `variable`, we determine the part of our code that `variable` should be **visible and accessible**. This permits the `variable` to exist within some boundaries, outside of these boundaries, the `variable` is inaccessible. 

**Every variable has a scope, If a variable is not in the current scope, it will not be available for use.**

JavaScript has the following kinds of scopes:
- Global Scope
- Local or function Scope
- Block Scope

### Global Scope
For `variables` **declared outside** of any `function` or curly braces `{}` the scope is the whole program (you can access such variables wherever you want). These are called global.

> If a variable is defined in the global scope, it is accessible anywhere in your code (including functions, objects, etc.)

See the code below :

```
let user = "Emmanuel";  // global scope

// any code below can access the user variable

function greetUser() {
// code here can also access the user variable
return user;
}
``` 
In the code above:

- The `user` variable is declared outside of the `greetUser` function giving it a  global scope.
- Any code we write can access the `user` variable.

### Local or function Scope

We can declare `variables` inside of a function. When `variables` are declared within a function, they are **only accessible within the function**. These variables are said to keep a local scope.

See the code below:
```
// code here cannot access the user variable

function greetUser(){
let user ="Emmanuel"  // user is a Local variable or has a local scope
//  any code here, have access to the user variable 
console.log(user)
}
//code here cannot access the user variable.
``` 
- In the code above, the `user` variable is declared inside the `greetUser` function hence, has a local scope. 
- Any code above or below the `greetUser` function cannot access the `user` variable
- Aside from the body of the   `greetUser` function, If you try accessing the `user` variable, you will get the `ReferenceError: user is not defined`

**Local variables get created when a function is declared and deleted when the function is executed.
**
See the examples below:

```
function isLocal(){
  const  user ="Emmanuel"
  console.log(user)
}

isLocal() // execute the function

console.log(`Where is ${user}`) // error 
``` 
The output of the code will be
- `Emmanuel`
- `ReferenceError: user is not defined`

The `error` is displayed because the `user` variable is deleted when the `isLocal()` function is executed.

**Because local variables are only accessible inside the body of the function, variables with the same name can be used in different functions**. 

See the code snippet below 

```
function greetUser(){
let user ="Emmanuel"  // user is a Local variable
//  any code here, have access to the user variable 
console.log(`Hi there ${user}`)
}

function sayHello(){
    let user="Emmanuel" // same variable name used in the sayHello function
    console.log(`Hello ${user}`)
}

//call both functions
greetUser()

sayHello()
``` 
The output of the code below will be :

```
Hi there Emmanuel
Hello Emmanuel
``` 

### Block Scope

Prior to ES6 (2015), JavaScript had only Global and Function Scope. The introduction of the `let` and `const` keywords in ES6 provided Block Scope in JavaScript.

> Variables declared within a code block or curly braces `{...}` have block scope, and cannot be accessed from outside the block.

For example

```
{
 // do some tasks with local variables that should not be seen outside

  let message = "Hello"; // only visible in this block

  alert(message); // Hello
}
// message can NOT be used here
alert(message); // Error: message is not defined

``` 
- We can use code blocks to separate a piece of code that does its own task, with variables that only belong to it.

![JavaScript Scope](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i64p4ld66pkcd1q2yoeh.jpg)


Let's now explore the concept of nested function.


## Nested Function

> A nested function is a function defined inside another function.

See the code below:

```
// Example 1
function getUserDetails(fName, lName){

// greetUser function is created inside the parent function

    function greetUser(fName,lName){
        return (`Hello ${fName} ${lName}`)
    }

//Example 2
function increaseCount(){
let count = 0;

// newCount is a nested function
return function newCount(){
return count++
}
}
``` 

`greetUser`, and "newCount" are nested functions because they are declared inside another function.

- A nested function can be returned, either as a property of a new object or as a result by itself. 
- The returned value can then be used somewhere else. Regardless of where it is used, it still has access to the same outer variables.
- In a nested function, we might have `variables` in the outer scope as well as the inner scope. 
- The variables of the outer scope are accessible inside the inner scope. 

In the examples above, the `greetUser` function is nested in the `getUserDetails` function. This permits the `greetUser`function to access the `fName` and `lName` variables passed as parameters in the outer function, `getUserDetails`. 

Likewise, the `newCount` function can access the outer variable `count`. 

Let's explore why the above is possible in the next topic.

### Lexical environment

During code execution, the JavaScript engine creates a special internal object called `Lexical environment.`This Lexical environment has an `environment record` which is an `object` created to store all local variables.

The lexical environment will be pre-populated with all declared variables in the code.

When a function executes, prior to its execution, the lexical environment provides the environment record to store the `parameters` and or `variables` declared in the body of the function.

If a variable is declared in the global scope, a lexical environment is also created to store the variable in the environment record.

Like the example above, when you declare a global `variable` and a `function`, you have  two lexical environments respectively:

- Outer environment
- Inner environment
- The `sumNum` is the inner environment whilst the `x` variable forms part of the outer environment.

## Lexical Scoping (Accessing variables declared in the outer scope)

> Lexical scoping describes how the JavaScript engine determines variable names when functions are nested.

**The term "lexical" relates to the fact that lexical scoping uses the location where a variable is declared within the code to determine where that variable is available.**

Consider a scenario where you live in a confined house with a lower fence wall. Within the house, you can **look outside** the fenced wall to have visibility of your environment (and access stuff outside the fenced wall).

Likewise in JavaScript, each scope can **"look outside"** to view the outer scope and access variables in the outer scope. Furthermore, nested functions can access variables declared in the outer scope.

**A variable defined in the global scope can be accessed inside the inner scope or any block scope even when it is not declared in the block scope. **

To rephrase, an inner or block scope can** "look outside"** to access variables declared in the global scope.

See the code below:

```
let x = 20; // global scope

function sumNum(){
// inner scope
  let y = 10;
  let z= 40;
  console.log(x+y+z)
}

//execute the function.
sumNum()
``` 
The output of the code will be `70`. Do you know why?

### Accessing a variable in the lexical environment

When a code wants to access a variable, the **environment record of the internal environment is searched first**, followed by the record in the outer environment, then the outer one, and so on, until it gets to the global scope. If the variable is not found anywhere, an  `error` will be thrown.

When the code above is executed:

- The `y` and `z` variables are instantly found in the **environment record of the internal environment** of the `sumNum` function.
- However, when the code wants to access the `x` variable, it cannot find the `x` variable declared in the `environment record` of the inner environment. 
- It "looks outside" the inner environment and searches the outer environment. It then finds the outer environment in the global scope and accesses the value stored in the `x` variable.
- Hence `console.log(x + y + z)` produces the expected  output of `70`.

**In effect, a block or function scope can look at its inner environment for a variable, if not found, it checks the outer environment for the variable, and if it was declared there, use the value declared in the outer environment. This concept is known as lexical scoping **

Take a look at this other example 

```
function outer(){
  let user="Emmanuel"; //local scope

// inner function

  function init(){
    console.log(user); 
  }  
  init()
}

//execute the outer function
outer()

``` 
`outer()` creates a local variable `user` and a function `init` which is an inner function. 
Note that the `init()` function has no declared variables. However, since inner functions have access to the variables declared in the outer functions, `init()` can access the `user` variable declared in the parent function, `outer()`.


## Function Returning a Function
In a nested function, when the outer function is executed, it can return an inner function. Because functions are values, the inner function can be assigned to a variable and executed later in our code.

See the code below

```
function outerFunction(){
  return function innerFunction(){
    //code goes here
  }
}

//return inner function and assign to a variable
const useFunction = outerFunction();
//useFunction stores the innerFunction
``` 
Take a look at this other example

```
function outer(){
  let a = 10
  return inner(){
    //code goes here
    let b = 20;
    console.log(a + b)
  }
}
//return inner function 
const getInner = outer()
``` 
Here we have two functions
- An outer function,` outer` which has a variable `a`, and returns an inner function `inner`
- The body of the inner function, we declare a variable `b` and assign it a value of `20`. 
- The inner function can have access to the outer variable `a`.
- The scope of the variable `a` is limited to the `outer` function, whilst the scope of the variable `b` is limited to the `inner` function.
- We then execute the `outer` function 

**Keep in mind, anytime we execute a function, any variables defined in the function scope cease to exist.
**
In effect, in the `console.log(a+b)`, the variable `b` exists prior to the execution of the `outer` function.
Once the outer function has been executed, the `b` variable, **no longer exists.**

What this means is that in `console.log(a+b)`, the variable `b` exists **only during the execution** of the `outer()` function. Once the outer function has **finished executing**, the variable `b` **no longer exists**.

Variables of a function are recreated anytime the function is called, and live up until the function completes execution.

**The question is, what happens to variables when the function call that created them has completed its execution?**

This question introduces the concept of `closure`. 

## Closure

From the above, we know that `variables` get deleted when the function that created them has completed its execution.

** Hence, it should not be technically possible to access the `b` variable in the inner function.**

That said, the inner function can access the variables of the surrounding function due to `closures` in JavaScript.

>  A closure gives you access to an outer function’s scope from an inner function.

**When an inner function is called, the function body remembers the environment in which it was created, not the environment in which it is called.**

Take note of this phrase, **"the environment in which it was created"**.  Because the inner function knows the place of birth ( environment in which it was created), the inner function preserves the scope chain of the surrounding function at the time the surrounding function (outer function) was executed.

Even though you will expect the variables declared in the outer function to be deleted after it has been called, the inner function has already **accessed and preserved **the variables in the outer function.

**The inner function then carries the preserved variables along with it (everywhere it goes)
**
The following code shows an example of this. It defines a function, `mainFunction`, that creates a local variable. It then returns a function that accesses and logs this local variable to the console. 

```
function mainFunction(name){
  let user= name //local variable
  return function innerFunction(){
    console.log(`Hello ${user}`)
  }
}

const callInner = mainFunction("Emma"); // execute mainFunction
console.log(callInner())
``` 
The output of the code above will be `Hello Emma`.

Let's explore the details:

- When the outer function `mainFunction` is executed, it returns an inner function that is assigned to the `calInner` variable
- This inner function remembers the **environment in which it was created** and hence it is able to access and preserve any variable in that environment.
- On execution of the `mainFunction()` we would expect the local variable `user` to get deleted. But note that, prior to its execution, the `innerFunction` was able to access and preserve the `user` variable declared in the outer scope.
- No matter where the `innerFunction` is called, we are still able to remember the variable it has preserved even when the `mainfunction` has finished execution. The `innerFunction` is a `closure`.
- Executing the `callInner()` function, therefore, produces the output  `Hello Emma`.


![JavaScript closure](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/455tigtazeukjdimbvle.jpg
)

### Examples of closures 
In this example, we want to create a function that allows us to send emails to users, the user reads the content of the mail when he clicks on the button. 

To achieve this, we declare two functions `composeMail` and `emailContent`. 

- `composeMail` will accept the `senderName` as a parameter
-  In the body of the `emailContent` we write the content of the email to send.
- Because these two functions are related, we will nest them, with the `composeMail` as an outer function and `emailContent` as an inner functon.
- The `emailContent` will be a `closure`, **it is able to look outside its scope and access and preserve any variable or parameter defined in the outer scope**.

We would also define a `click` event listener, that listens for a click of a button to enable us to read the content of the email.

Examine the code below:

```
const btn = document.getElementById("btn") // access a button element with id "btn"

// define composeMail and emailContent functions

const composeMail = (senderName)=> {

// nested function
  const emailContent = (content)=> {
    return `Hi ${senderName},${content}`
  }
  return emailContent
}

// execute the composeMail
const readEmail = composeMail("Emmanuel"); 

// view content of mail
function viewInbox(){
  console.log(readEmail(`Your article on Closures is receiving a lot of views, Congrats !!!`));
  
}

// add a click event listener
btn.addEventListener('click',viewInbox)
``` 
The output of the code will be 

```
Hi Emmanuel,Your article on Closures is receiving a lot of views, Congrats !!!
``` 

Let's walk through the code step by step

1. We access the button element defined in our `html` and assign it to `btn` variable
2. We define the `composeMail` and `emailContent` functions.
3. The `composeMail` accepts a parameter `senderName` which when executed, will receive the name of the user to send the email.
4. When the `composeMail` is executed, it returns the  `emailContent` function which we assign to the `readMail` variable to be executed later.
5. Prior to the execution of the `composeMail` function, the `emailContent` is able to **access and preserve** any variable declared in the `composeMail` .For this instance, it will be `senderName`. 
6. On execution of the `composeMail` function, the returned function is assigned to `readMail`
7. The `emailContent` function has **safely stored** the `senderName` variable hence anywhere we execute the `emailContent` we still have access to the value passed to the `composeMail` during execution.
8. Finally, we define the `viewInbox` function and in the body of the function we execute the `emailContent`.
9. Now, on click of a button, the `viewInbox` function is executed, and the `emailContent` function still has access to the `senderName` variable.
10. We can now say the `emailContent` function is a `closure`.


#### Eg.2 Which variables are accessible?
Which of the `timeOfDay`variables is accessible, in the code below?


```
function greetUser(name) {
  let timeOfDay = "Good evening";

//define another function
  return function() {
    console.log(`${timeOfDay} ${name}, what would you like to do today`);
  };
}

let timeOfDay = "Good morning"; // change time of day

// run the greetUser function
let greeting = greetUser("Emmanuel");

// call the returned function
greeting(); // what will it show?
``` 
In the example above, the function `greetUser` has a local variable `timeOfDay`, it also creates another anonymous function. That new function can be called **somewhere else in our code.**

In the global scope, we also declare another `timeOfDay` variable and assign a value to it.

When we execute the return function, which of the `timeOfDay` variable will it access, and what would be the final output?

Result:

```
"Good evening Emmanuel, what would you like to do today"
``` 
Explanation:

- Regardless of where this new function is called, it will have access to **its outer variable from its creation place**, and **not the invocation place**. Creation refers to where the function was first defined ( place of birth)
- The value of the  `timeOfDay`variable at its place of birth `Good evening` and **not** `Good morning.`, hence the output.
 

Note that, if there were no `timeOfDay` variable in the `greetUser` function, then we would search outside that function, for it, and it would be found in the global scope. 

In that case, the value of the variable will be:`Good morning`. Hence the result would be `Good morning Emmanuel, what would you like to do today.`

**The ability to reference a specific instance of a local variable in a surrounding scope is called `closure`.
**
A function that references variables from local scopes around it is called a `closure`. 

This action not only frees you from having to worry about the lifetime of variables but also makes it possible to use function values in unique methods.

### The Scope Chains in Closure

In `closure`, the inner function has three scope chains:

- Access to its own scope: variables declared between its curly braces `{}`
- Access to the outer function’s variables: variables declared outside the inner function
- Access to any global variables that may be defined

Let's wrap up with another example:

```
const lessonNum = 2; //global variable
const learnFruit = (fruit) => {
  const fruitName = fruit; // variable in the outer scope
  
//inner function

  return getFruit = (fruit)=>{
    let userName ="Emmanuel"; //inner variable
    console.log(`Hello ${userName},welcome to lesson number ${lessonNum},here you learn about fruits.The fruit you picked is ${fruitName},and it begins with the letter ${(fruitName.charAt(0)).toUpperCase()}`)
  }
}

const sayAlphabet = learnFruit('mango');

// execute the inner function
sayAlphabet()
``` 

- Executing `learnFruit` returns the inner function `getFruit` which is a `closure`.
- The `getFruit` has access to three scope chains:

1. The `lessonNum` variable in the global scope
2. The `fruitName` variable in the outer scope
3. The `userName` variable in the inner scope

To reiterate the concept of closure, once the `learnFruit()` has been executed, we would have expected the variable declared in its scope to be **deleted**. 

However, prior to execution, the `getFruit` function is able to **access and keep copies of the outer variables**. 

Regardless of where the `getFruit` is run, we can still use any variables defined in the scope chain.

### Rule of Thumb

> A rule of thumb to identify a closure: if inside a function you see a strange variable (not defined inside that function), most likely that function is a closure. Because the strange variable has been captured and preserved.

### Importance of closures
Closures permit you to save a snapshot of the scope where the function was initially declared.

Because they exist within outer functions, it allows you to run the outer function, and execute the inner function (closure) later, with the values from the outer function saved.

This is  optimal than calling two different functions if these two functions are linked because it empowers you to write clean and maintainable code 

## In summary
Closure is like keeping a copy of the local variables of the function.

It helps eliminate the duplication of effort with a program or to hold values that need to be reused throughout a program so that the program doesn't need to recalculate the value each time it's used.

I would love to read your input on this article, kindly leave a comment below. Don't forget to follow me on [Twitter](https://twitter.com/emmanuelfkumah), and share this article to help others