what is Closure?

A closure is the combination of a function bundled together with references to its the lexical environment.

function x(){
	var a = 7;
	function y() {
	console.log(a);
	}
	y();
}
x(); // 7

what about this code,

function x() {
  var a = 7;
  return function y() {
    console.log(a);
  };
  y();
}
var z = x();
z(); // still 7

because, function x() returns closure (not only function) so it still remembers the reference to the variable a , hence logs “7”.

Corner cases

function x() {
  var a = 7;
  return function y() {
    a = 100;
    console.log(a);
  };
  y();
}
var z = x();
z(); // 100
function z() {
  var b = 900;
  function x() {
    var a = 7;
    return function y() {
      console.log(a, b);
    };
    y();
  }
  x();
}
z();
Closure

Use cases;

  1. Module deign pattern
  2. currying
  3. functions like once
  4. memoize
  5. maintaining state in async world
  6. setTimeouts
  7. Iterators
  8. and many more.

Disadvantages

  1. more memory consumption

Interview questions

function x() {
  var i = 1;

  setTimeout(function () {
    console.log(i);
  }, 1000);

  console.log("what logs first");
}
x();

/*
OUTPUT :
what logs first
1
*/

JavaScript does not wait for setTimeout to expire, it takes closure and attaches a timer with it, and continues the execution. when timer expires, the setTimeout is executed.

// this program is suppose to print 1 through 5 after each second.
// IT DOES NOT ? WHY ??

function x() {
  for (var i = 1; i <= 5; i++) {
    setTimeout(function () {
      console.log(i);
    }, i * 1000);
  }
}

what happens in this code ?

  • for i: 1 to 5 , a new setTimeout is created in memory with the closure of variable i
  • all 5 setTimeout has reference to same variable i
  • for loop is executed before any setTimeout can even execute so i becomes 6.
  • then each setTimeout executes with the reference value of i whose value is now 6.

how do we fix this?

  1. use let keyword
/*
	let is block scope so each setTimeout have seperate copy if i.
*/
function x() {
  for (let i = 1; i <= 5; i++) {
    setTimeout(function () {
      console.log(i);
    }, i * 1000);
  }
}
  1. closure of the closure
/*
	here each coc() has its own execution context hence each has its onw variable i in memory stage. so it works !!
*/
function x() {
  for (var i = 1; i <= 5; i++) {
    function coc(x) {
      setTimeout(function () {
        console.log(x);
      }, x * 1000);
    }
    coc(i);
  }
}

data hiding and encapsulation

  • data hiding refers to hiding data so that other functions cant access it.
function counter(){
	var count = 0;
	return function incrementCounter(){
		count++;
		console.log(count);
	}
}

// we can not modify count outside fn counter()

var counter1 = counter();
counter1();  // > 1
counter1();  // > 2

var counter2 = counter();
counter2();  // > 1
counter2();  // > 2
counter2();  // > 3

// as you can see we can create different counters from counter();
// all will be different copy from each other.

can you make above code scalable ?

// we can make constructor function of the counter to make scalable, so if we want to add new functions like decrement, we can!!

function Counter() {
  //good naming convention
  var count = 0;

  this.increamentCounter = function () {
    count++;
    console.log(count);
  };
  this.increamentCounter = function () {
    count++;
    console.log(count);
  };
}

smart garbage collection

function x() {
  var i = 1,
    j = 10;
  return function b() {
    console.log(i); //> at this point j is not required so it is handled by garbage collector.
  };
}
let y = x();
y();