JavaScript Closure 101: An Introduction to the Fundamentals

Photo by Pakata Goh on Unsplash

JavaScript Closure 101: An Introduction to the Fundamentals

Learn about the concept of closure in JavaScript, including how it works and how it can be used to create private variables or pass functions around.

Table of contents

No heading

No headings in the article.

JavaScript's closure feature enables developers to compose functions with access to variables beyond their scope. This makes it perfect for creating both private data and functions, as well as callable objects that can be used in different contexts. In this blog post, we'll delve into how closure works and how you can use it practically.

If you're looking to learn more about the advantages of closures in JavaScript, click the link to check it out.

First, let's start by looking at how closures are created in JavaScript. A closure is created when a function is defined inside of another function, and the inner function has access to the variables and parameters of the outer function. Here is a simple example:

function outerFunction(param) {
  const outerVariable = 'I am a variable in the outer function';

  function innerFunction() {
    console.log(outerVariable);
    console.log(param);
  }

  return innerFunction;
}

const closure = outerFunction('I am a parameter');
closure();
// I am a variable in the outer function
// I am a parameter

In this example, the innerFunction has access to the outerVariable and the param variable, even though they are defined outside of its own scope. When the closure is created by calling outerFunction and assigning the returned innerFunction to the closure variable, the innerFunction maintains a reference to the outerVariable and param. This means that when the closure is called, it is able to access and use these variables, even though they are no longer in the same scope.

One important thing to note is that the closure maintains a reference to the variables, not a copy of the values. This means that if the outerVariable is changed after the closure is created, the closure will have access to the updated value. For example:

function outerFunction() {
  var outerVariable = 'I am a variable in the outer function';

  function innerFunction() {
    console.log(outerVariable);
  }

  return innerFunction;
}

const closure = outerFunction('I am a parameter');
outerVariable = 'I am now a different value';
closure(); // 'I am now a different value'

In this case, when the closure is called, it will log 'I am now a different value' instead of the original value of outerVariable.

Now that we have a basic understanding of how closures work, let's look at some practical applications. One common use for closures is to create private variables and functions. Since the inner function has access to the variables and parameters of the outer function, it can use these to create private variables and functions that are not accessible from the outside. Here is an example of a closure used to create a private counter:

function counter() {
  let count = 0;

  return function() {
    count++;
    console.log(count);
  }
}

const closure = counter();
closure(); // 1
closure(); // 2
closure(); // 3

In this example, the count variable is defined inside the counter function and is not accessible from the outside. However, the inner function returned by the counter function has access to count and is able to modify its value. This allows us to create a simple counter that can be incremented, but the count variable is not directly accessible from the outside and cannot be modified except through the use of closure.

Another common use for closures is to create functions that can be used in different contexts. For example, consider the following code:

function greet(greeting) {
  return function (name) {
    console.log(greeting + ", " + name);
  };
}

const sayHello = greet("Hello");
sayHello("John"); // 'Hello, John'
sayHello("Jane"); // 'Hello, Jane'

const sayHi = greet("Hi");
sayHi("John"); // 'Hi, John'
sayHi("Jane"); // 'Hi, Jane'

In this example, we have defined a greet function that takes a greeting as a parameter and returns a function that takes a name as a parameter and logs the greeting and name. We then create two different closures using the greet function, one for saying hello and one for saying hi. These closures can be used in different contexts, allowing us to easily reuse the same greeting logic with different greetings. Closures can also be useful for creating functions that need to maintain state. For example, consider the following code:

function createAdder(x) {
  return function (y) {
    return x + y;
  };
}

const add5 = createAdder(5);
console.log(add5(3)); // 8
console.log(add5(4)); // 9

const add10 = createAdder(10);
console.log(add10(3)); // 13
console.log(add10(4)); // 14

In this example, we have defined a createAdder function that takes a number as a parameter and returns a function that takes another number as a parameter and returns the sum of the two numbers. We then create two different closures using the createAdder function, one for adding 5 and one for adding 10. These closures are able to maintain their own state, allowing us to easily create adder functions for different values.

There are many other ways in which closures can be used in JavaScript, and they are an important concept to understand for anyone working with the language. Whether you are creating private variables, passing functions around, or maintaining state, closures can be a powerful tool in your JavaScript toolkit.

Visit Frontend Mag to read more useful front-end web development articles!