Closures

arfat.dev

Scope

The scope is an enclosing context in which a variable is associated with a value and is accessible.

let x = 10;

function foo(arg) {
  let x = 20;
  if (arg > 100) {
    let x = 30;
  }
}

foo(400)
Refinement of concepts

Important Note:

The inner scopes (or nested blocks) always have access to their parent's, grandparent's, great-graparent's etc. scope.

That means:

if-block can access

  • foo's scope (parent)
  • Global scope (grand parent)

foo-block can access

  • Global scope (parent)

The name resolution (or search) always begins in the current scope and then climbs to outer scopes in order.

arfat.dev

Example 📖

let myName = 'in outer scope';

function printName() {
  console.log(myName);
}

printName(); // in outer scope

myName = 'name changed';

printName(); // name changed

Lexical Scope

In short:

an identifier refers to its nearest lexical environment.

"Lexical" means that the as "nesting of scopes that is visible by looking at the source code"

aka Static Scope

"Lexical" means that a scope ONLY has access to values which are part of it's hierarchy in the source code.

Now, Lexical Scope mean that:

You always start the name resolution search at the point of function definition / declaration. NOT at the point of execution.

Example 📖

function sum(a, b) {
  let total = a + b;
  return total;
}

function anotherFunction() {
  let total = 5230;
  let returnedValue = sum(19, 200);
  console.log(returnedValue); // 219
}

Note:

sum and anotherFunction both have access to the same global scope.

First-class values

In a programming language, a first-class value is a value which can be

  • created
  • modified
  • assigned to a variable.
  • passed as an argument,
  • returned from a function

Are numbers first class in JS?

What about strings?

In JS, functions are also

first-class 🔥

Functions within Functions

function printerWith(str) {
  return function (newStr) {
    return newStr + str;
  };
}

setTimeout( function () {
  console.log('in a callback function')
}, 1000)

When a function is passed as an argument, it's called as (generally) callback.

Closures

A closure refers to the ability of a function to

  • remember its lexical parent scope
  • have read/write access to variables defined in the parent environment
function a() {
  var x = 5;
  return function () {
    console.log(x);
  };
}

var x = 10;
const b = a();
b();
  • The red is global scope
  • The green is a's scope
  • The blue is anonymous function's scope

Test

for (var i = 0; i < 3; i++) {
  setTimeout(function log() {
    console.log(i);
  }, 1000);
}

Test

function a() {
  let fn;
  {
    var x = 5;
    fn = function() {
      console.log(x);
    }
  }

  return fn;
}

var x = 10;
const b = a();
b();

Test

var a = 100;

function abc(x) {
  var a = 10;
  return function (y) {
    return a + y;
  }
}

a = 50;

var inner = abc(20);

function foo() {
  var a = 30;
  console.log(inner(5));
}

foo();

Test

var e = 10;
function sum(a) {
  return function(b) {
    return function(c) {
      return function(d) {
        return a + b + c + d + e;
      }
    }
  }
}

sum(1)(2)(3)

Test

That is, all inner functions share the same parent environment.

let firstClosure;
let secondClosure;
 
function foo() {
 
  let x = 1;
 
  firstClosure = function () { return ++x; };
  secondClosure = function () { return --x; };
 
  x = 2;
 
  console.log(firstClosure());
}
 
foo();
 
console.log(firstClosure()); 
console.log(secondClosure());

3

4

3

function printerWith(str) {
  return function (newStr) {
    return newStr + str;
  };
}

const fn1 = printerWith('!');
const fn2 = printerWith('?');

let returnedValue = fn1('arfat');

console.log(returnedValue);

Test

arfat!

Closures

By Arfat Salman

Closures

Just JS Closures with examples

  • 880