DEV Community

Mario
Mario

Posted on • Originally published at mariokandut.com on

What is Closure Scope?

When a function is created in Javascript, a closure is created with it at the same time, but what is a closure?

Closures

A closure is a combination of the function bundled together with the references to its surrounding state, or a bit more abstract, think of a closure as an invisible object that stores variables and parameters created in the function.

Lexical scoping

Lexical scoping describes how a parser resolves variable names when functions are nested. The word lexical refers to the fact that lexical scoping uses the location where a variable is declared within the source code to determine where that variable is available. Nested functions have access to variables declared in their outer scope.

Let's have a look at an example of lexical scoping:

function init() {
  let name = 'Mario'; // name is a local variable created by init
  function displayName() {
    // displayName() is the inner function, a closure
    alert(name); // use variable declared in the parent function
  }
  displayName();
}
init();
Enter fullscreen mode Exit fullscreen mode

The function displayName() has no local variable on their own. It's an inner function and has access to the variables of the outer function.

Closure

A closure is the combination of a function , and the lexical environment within which that function was declared. Let's look at some code:

function alertDisplayName() {
  let name = 'Mario';
  function displayName() {
    alert(name);
  }
  return displayName();
}
const myFunction = alertDisplayName();
myFunction();
Enter fullscreen mode Exit fullscreen mode

Running this code would have the same effect as the init() function from above. The displayName() inner function is returned from the outer function before being executed.

At first this might seem not correct, that the code run successfully. It depends on your programming background, in some languages, local variables within function only exist during the function's execution. In JavaScript functions form closures. A closure is the combination of a function, and the lexical environment within which that function was declared. This lexical environment or static context consists of any local variables that were in-scope at the time the closure was created. Closures are created at the same time functions are created.

In the code example above, myFunction is a reference to the instance of the function displayName that is created when alertDisplayName runs. The instance of displayName maintains a reference to its lexical environment, within which the variable name exists. Hence, when myFunction runs, the variable name remains available for use, and Mario is passed to alert.

Let's look at another piece of code:

function addNumbers(num1) {
  return function(num2) {
    return num1 + num2;
  };
}
const add3 = addNumbers(3);

console.log(add3(3)); // will log 6
Enter fullscreen mode Exit fullscreen mode

The function addNumbers is in essence a function factory. It creates a function, that can add a specific value to their argument. The lexical environment stored for the constant add3 would be for num1=3.

Closures are useful , because they let you associate data (the lexical environment) with a function that operates on that data.

Another example of encapsulating state using closure scope would be to enclose a secret:

unction createSigner (secret) {
  const keypair = createKeypair(secret)
  return function (content) {
     return {
        signed: cryptoSign(content, keypair.privateKey),
        publicKey: keypair.publicKey
     }
  }
}
const sign = createSigner('super secret thing');
const signedContent = sign('sign me');
const moreSignedContent = sign('sign me as well');
Enter fullscreen mode Exit fullscreen mode

In the code snippet above createKeypair and cryptoSign are purely for outlining the concept of the encapsulation of secrets.

Closure scope can also be used as an alternative to prototypal inheritance, but it doesn't use the prototype chain nor does it rely on the implicit this keyword.

function animal(name) {
  const eat = () => {
    console.log(name + ' eats');
  };
  return { eat };
}

function dog(name) {
  name = name + ' the dog';
  const bark = () => {
    console.log(name + ' barks');
  };
  return {
    ...animal(name),
    bark,
  };
}
const henry = dog('Henry');

henry.eat(); // prints "Henry the dog eats"
henry.bark(); // prints "Henry the dog barks"
Enter fullscreen mode Exit fullscreen mode

The advantage of using closure scope to compose objects is that it eliminates the complexity of prototypes , context (this) and the need to call a function with new (which can have unintended side effects when omitted ). The downside is that where a prototype method is shared between multiple instances, an approach using closure scope requires that internal functions are created per instance. JavaScript's engines use increasingly sophisticated optimization techniques internally, so it's only important to be fast enough for any given use case.

It's recommended to use function composition over prototypal inheritance and optimize at a later point if required.

TL;DR

  • When a function is created in Javascript, a closure is created with it
  • A closure is a combination of the function bundled together with the references to its surrounding state

Thanks for reading and if you have any questions , use the comment function or send me a message @mariokandut.

If you want to know more about Javascript , have a look at these Javascript Tutorials.

References (and Big thanks)

MDN, JSNAD

Top comments (2)

Collapse
 
khizerrehandev profile image
khizerrehandev • Edited

Excellent explanation.

Just need to add that internally closures maintain a seperate memory allocation of its lexical environment that is why when closure returned function is returned.
it looks to allocated memory for lookup process to find variable that was enclosed at the time of closure. I hope my understanding is correct ;)

Collapse
 
mariokandut profile image
Mario

Yes, exactly. Well explained. :) The inner function has there own lexical or static scope, and in the lookup process it looks first in the "own" memory.