const makeCounter = () => {
  let count = 0;
  return () => {
    count++;
    console.log(count);
  }
}

let counter = makeCounter();
counter(); // logs 1
counter(); // logs 2
counter(); // logs 3
ex1
function memoize(fn){
  let cnt = 0  // cnt is private var,can only access by the callfn object 
  function decrease(){
    fn(cnt--)
  }
  function increase(){
    fn(cnt++)
  }
  return {decrease,increase}
}

function repeatfn(count){
  console.log("calculating...",count)
}

const callfn = memoize(repeatfn)
callfn.decrease() 
callfn.decrease() 
callfn.increase() 
callfn.increase() 
callfn.increase() 

ex2
function memoize(fn){
  let cache = {}
  
  return function(num){
    if(cache[num]) return cache[num]
    let res = fn(num)
    cache[num] = res
    return res
  }
}

function square(n){
  console.log("calculating...",n)
  return n*n
}

const callfn = memoize(square)
console.log(callfn(2))
console.log(callfn(2))
console.log(callfn(7))

ex3
function multiplier(factor) {
  return function (number) {
    return number * factor;
  };
}

const double = multiplier(2);
console.log(double(5)); // 10

real project usecase

function createNotifier() {
  let lastShown = 0;

  return function (message) {
    const now = Date.now();
    if (now - lastShown > 3000) {
      console.log("🔔", message); // Replace with UI toast
      lastShown = now;
    } else {
      console.log("❌ Notification blocked (too soon)");
    }
  };
}

const notify = createNotifier();

// Simulate user actions
notify("Welcome!"); // ✅ Shows
setTimeout(() => notify("Clicked again"), 1000); // ❌ Too soon
setTimeout(() => notify("3 seconds passed"), 3100); // ✅ Shows

It remembers the last time a notification was shown, across multiple calls.
No global variables needed — totally encapsulated.