JavaScript Function Closures and Scope: 
How Best To Leverage Closure in JavaScript.

JavaScript Function Closures and Scope: How Best To Leverage Closure in JavaScript.

What is Closure in JavaScript?

In JavaScript, closures refer to the combination of a function and the lexical environment in which that function was declared. A closure is a function that references variables in the outer scope from its inner scope.

A closure is created, every time a function is declared. What does this mean, and how best can we leverage closure in JavaScript? What does a closure look like? What is the value and impact of the closure on our code?

To understand how to leverage closure in our code in JavaScript, firstly we have to understand what scope is in JavaScript and how it is used.

What is Scope?

In JavaScript, scope determines how variables in JavaScript are accessed. The scope is created when you run a function in JavaScript and this creates a new runtime scope. This describes the set of variables which are referred to as identifiers, that are available for that function to use. Scope in JavaScript determines the accessibility of variables, objects, and functions from different parts of the code.

Application of Scope in JavaScript.

There are three main types of scopes in JavaScript. But before ES6 (2015), JavaScript has only function scope and global scope but with the introduction of ES6 came new keywords like let and const. These new keywords let and const provide the block scope in JavaScript.

Four areas of scopes in JavaScript

Function scope

Local Scope

Global scope

Block Scope

Function Scope

In JavaScript, each function creates a new scope when variables are declared inside a function. This variable declared inside a function scope cannot be accessed from outside the function. Each function creates a new scope in a function declaration. The variables declared with var, let and const can have a function scope when declared inside a function.

Examples of function scope declaration

Local scope Variable

Local scope variables have function scope.

When a variable is declared within a JavaScript function it becomes local to the function it is declared within and can only be accessed from within this function. This makes it possible to use variables with the same name in different functions because local variables are only recognized inside their function.

When is a local variable in the function scope created? Local variables are created at the start of a function and ceased to exist anymore once the function does not exist anymore or is completed.

Examples of a local scope

// code here cannot use the local scope variable
function myPet() {
    //local scope variable
  let petName = "Manny";
  console.log(petName)
}
myPet(); // Output Manny

Global Scope Variable

In Javascript, the global scope variable is declared outside the javascript function, basically at the top of the function declaration. Global scope variables can be accessed anywhere in JavaScript.

Examples of global scope variables

The variable keywords var, let, and const can be declared in the global scope. var x = 3; let x = 3; const x = 3;

//Global scope variable
let man = "John";
function myGender(){
    //local scope variable
    let gender = "Male";
    console.log(gender + " " + man);
}
myGender(); //Output of the local variable: Male John
//console.log(gender + " " + man); // will give ReferenceError: gender is not defined

Other methods of accessing global scope variables

Method 1

Assigning a global scope variable when the value of a global variable can be changed inside a function.

// The global variable scope can be changed inside the function
let carName = "Nissan";
function autoName(){
    carName = "Toyota";
}
//before the function call
console.log(carName); //Nissan
//the value of carName changes after the function call
autoName(); // Nissan
console.log(carName); //Toyota

Method 2. Automatically global scope variable

In JavaScript, a variable can become a global scope variable if a value is assigned to a variable that is not yet declared. The value is used without declaring it. It automatically becomes a global variable. The example below shows a value that is declared inside a function without a keyword variable. It automatically becomes a global variable.

function greet() {
//global scope
    hello = "My World"
}
greet();
console.log(hello); //output My World
//This becomes a global scope as the value of the variable is declared with the let keyword. 
// if the value is declared with let hello = "My World"., it will throw an error.

LEXICAL SCOPING

In block Scope, the scope variable can only be accessed in the immediate block. It can only be accessed inside the if statement block. The third console trying to access the blocked scope variable outside the block will throw an error.

//global scope
let myName = "Emmy";
function familyName(){
    //local scope
    let fullName = "Nothingale";
    console.log(myName + " " + fullName);
}
familyName(); // Emmy Nothingale

The variable myName is a global scope variable that is accessible from anywhere including within the familyName() function.

The variable myName changes after the function call.

The variable fullName is a local scope variable that is accessible only within the familyName().

To access the fullName variable outside the familyName() function will throw an error.

Nesting in Lexical Scoping

Mastering the concept of scoping functions and lexical scoping helps you understand the application of javascript closures.

In lexical scoping, the scopes can be nested and the inner function can access the variables declared. Nesting in lexical scoping comes with the parent and child function, the child function nested inside the parent function.

function greetings() {
    let morning = "Good morning";
    function sayHello() {
        console.log(morning);
    }
    sayHi();
}
greeting(); // Good morning

The greetings() function is the parent function that creates a local variable let morning

The child function is the sayHello() function nested inside the greetings() function.

The child function sayHello() is accessible from within the body of the greetings() function.

The sayHello() function accesses the variables of the outer function message variable of the greetings() function.

Nesting with a return function

In Javascript, you can return a function from another function. The nesting of the child function within the parent function returns another function.

function morningGreeting() {
    let morning = "Good morning Manny";
    function sayHi() {
        console.log(morning);
    }
    return sayHi();
}
let hi = morningGreeting();  // Good morning Manny

The greeting() function returns the sayHi() function that is nested inside it and acts as the holder of the entire function.

Advanced Closure Application

function todayGreeting(days) {
    return function(week) {
        return days + " " + week;
    } 
}
let weekday = todayGreeting('today');
let monthly = todayGreeting('month');
console.log(weekday('monday'));
console.log(monthly('January'));

The todayGreeting() function takes one argument "days" and returns a function that accepts a single argument named "month".

The return function returns a combination of days and week variables, the todayGreeting() function behaves like a holder function for the entire closure that creates weekday() and monthly() with respective messages.

The weekday() and monthly() are closures and they share the same function body but different scopes. In the weekday() closure, the message is today while in the monthly() closure the message is in January.

Block scope nested inside global scope variable

//global scope
let firstName = "Johnson"
function genderName() {
    //local scope variable
    let middleName = "Tony";
    console.log( firstName + " " + middleName);
    if (middleName == "Tony") {
        //block scope variable
        let familyName = "Owusu";
        console.log(firstName + " " + middleName + " " + familyName);
    }
    // variable c cannot be accessed here
    console.log(firstName + " " + middleName + " " + familyName);
}
genderName(); // Johnson Tony Owusu

The block scope named let familyName is declared inside the if statement block and can only be accessed inside the if statement block.

To study more on JavaScript scopes and closures check out these study materials: w3chool JavaScript Scope and MDN Scope