How does JavaScript Closure work?

JavaScript

You may have already heard it as a keyword if you are a newbie JavaScript Developer but most of them probably haven’t. Or you are a developer who is looking for new opportunities and never used closure before but knows that it is crucial for job interviews of JavaScript Developer positions.

Generally to understand closure, reading one article is not enough. But in this article, you will learn all the used concepts to explain it and how these concepts work together loud and clear.

The closure is storing the current definitions and scope information in a function to pass it to outer scopes. Normally inner scope can not be accessible from outer scopes in the Lexical Scope environment.

This definition can be look intimidating at the beginning but please just focus on the keywords for now. Let me first begin with the scope keyword which will also tell you about Lexical Scope.

Scope

The scope is a fundamental concept in programming which takes care of name bindings. When we declare a function or variable in a block of the code, these name bindings can be accessible or inaccessible from other parts of the code. We called it generally as scope.

Programming languages are built on top of that scope concept to support security and durability for developers.

There are two common scoping approaches as Lexical (Static) Scope and Dynamic Scope.

Most of the known programming languages are using Lexical Scope which is also called Static Scope. These programming languages are C, C++, Java, JavaScript, Python and so on.

In Perl and Lisp, you can prefer to use Dynamic Scope. But also Logo as a programming language is built top of the Dynamic Scope.

So let me begin with the Lexical (Static) Scope first.

Lexical (Static) Scope

In the Lexical Scope environment, the name bindings are determined at compile time which is also called early binding. It comes with strict accessibility rules for the name bindings. We can describe these rules basically:

  • An inner scope can access to its outer scopes
  • An outer scope cannot access to its inner scopes.

So we can say in a Lexical Scope environment we have one-way access from an inner scope to outer scopes. For developers, this scoping strategy is easy to read and follow the code.

Dynamic Scope

In the Dynamic Scope environment, the name bindings are determined at runtime which is also called late binding and unlike Lexical Scope, Dynamic Scope doesn’t have accessibility limitations for the name bindings.

In this scoping strategy, it easy to implement as a programming language but it is difficult to follow current values of variables for the developers. Because for each name binding in different parts of the code, there will be a race condition for a similar function or variable names.

Of course, these definitions will not be enough to show you what they briefly are. So let’s look at those scoping strategies in a versus.

Lexical (Static) Scope vs Dynamic Scope

This is a just basic JavaScript code snippet:

let a = 1;
const printParentScopeA = () => {
  console.log(a);
}

const printChildScopeA = () => {
  let a = 10;
  console.log(a);
}

printChildScopeA();
printParentScopeA();

In this code snippet, we have a total of 3 scope definitions as:

  • Global scope
  • function printParentScopeA scope
  • function printChildScopeA scope
  1. When printChildScopeA() function is called, it prints the “a” variable defined in its scope which is function printChildScopeA scope. So it prints 10 right away.
  2. When printParentScopeA() function is called, it first looks for the “a” variable definition and couldn’t find in its scope which is function printParentScopeA scope. Then searches the upper scopes for the “a” definition and finds it in the Global scope. So it prints 1.

The followed scoping logic is the Lexical (Static) Scope.

Let assume that it is a Dynamic Scope environment instead of Lexical Scope, what could be the output?

In this case, all function and variable definitions will store in a general scope and all same name declarations will be pointed to the same variable or function and the last same-named definition or declaration will have the final effect on others.

Thus in Dynamic Scope environment, our code snippet will work as:

  1. When printChildScopeA() function is called, first it will change the “a” variable value to 10 whose definition is stored in a general scope. Then it prints the “a” variable defined in the general scope. So it prints 10.
  2. When printParentScopeA() function is called, it looks for the “a” variable definition in general scope then finds it with a value of 10. So it prints 10 again.

As you can see, it an unusual behavior and it is hard to follow for larger codebases. That is why most of the programming languages are built on top of the Lexical (Static) Scope.

Now you understood what is Lexical Scope exactly and how it defines the scopes and searches name bindings in these scope definitions.

Now finally, we can talk about JavaScript Closure.

Closure

Thanks to closures we can bundle a lexical scope environment and pass it to outer scopes. As you read before normally it is not allowed to reach inner scope environments in Lexical Scope but Closure is an essential JavaScript feature that allows us.

Ok, how can we do this?

We can encapsulate a lexical environment by defining a function in another function. At this definition processes, we can store current lexical scope content in the inner function definition.

So let’s look at this simple closure example.

Closure Example

const powerOf = (x) => {
  const power = (y) => {
    return y**x;
  };
  return power;
}

const square = powerOf(2);
const cube = powerOf(3);

console.log(square(2));  // prints 4
console.log(cube(2)); // prints 8

In the code snippet above, you can see when the powerOf() function is called with a parameter, it is returning the power() function instead of executing it and during this function returning process, y parameter and the current value of x variable are preserved.

Thus when powerOf(2) is called, it is returning:

((y) => {
  return y**2;
});

And when powerOf(3) is called, it is returning:

((y) => {
  return y**3;
});

So we stored the power() function current definitions and lexical scope in a bundle thanks to JavaScipt Closure and we have obtained the different function definitions as square() and cube() from a single function definition.

JavaScript Closure is a very strong feature that is even used for implementing a design pattern called Module Pattern. Thanks to this implementation JavaScript can have encapsulation without public, private keywords.

For module pattern implementation, JavaScript also uses another strong feature which is called Immediately Invoked Function Expression (IIFE).

What is IIFE?

Immediately Invoked Function Expression (IIFE)

IIFE is a very basic JavaScript feature that enables us to run the function during its definition process.

A simple IIFE example is:

(() => {
  console.log(‘I am an IIFE’);
})(); // prints: I am an IIFE

In the example above, it prints “I am an IIFE” right away without waiting for a separate function invocation.

To implement Module Pattern, we will define our functions inside of an IIFE which is possible with Closure.

Module Pattern Implementation

Here a basic Module Pattern implementation example:

var myModule = ((() => {
  var myPrivateVariable = ‘private’;
  var myPublicVariable = ‘public’;
  var myPrivateMethod = () => {
    console.log(myPrivateVariable);
  }
  return {
    myPublicVariable,
    myPublicMethod: () => {
      myPrivateMethod();
    }
  };
})());

console.log(myModule.myPublicVariable);
// prints: public

myModule.myPublicMethod();
// prints: private

console.log(myModule.myPrivateVariable);
// prints: undefined

myModule.myPrivateMethod(); 
// throws TypeError: myModule.myPrivateMethod is not a function

As you can see from the above example, we have defined public and private variables and functions in an IIFE.

By deciding which of them should be returned, we make them public. If you don’t return your variable of function in your module definition, it will become a private one.

If you try to access your private variable, it will be undefined. If you try to access your private function, it will throw a type error.

Module Pattern is a very common pattern in JavaScript and it is easy to implement thanks to IIFE and Closure.

Conclusion

I hope now you clearly understood what is JavaScript closure and how it works. Also with the Module Pattern example, I hope you see a common usage of Closure and IIFE in JavaScript.

If you want to learn more about Web Development, don’t forget to subscribe to our newsletter and if you have any questions, please don’t hesitate to contact me.

See you in new articles.

Leave a Reply

Your email address will not be published. Required fields are marked *