# Closure

# 🔹 What is a Closure?

A **closure** is created when a function **remembers the variables from its outer scope** even after that outer function has finished executing.

👉 In simple words:  
**Inner functions can access variables of their outer function even after the outer function has returned.**

---

### Example 1: Basic Closure

```javascript
function outer() {
  let count = 0;  // outer variable

  function inner() {
    count++;  // inner function using outer variable
    return count;
  }

  return inner;
}

const counter = outer();  
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
```

✅ Even though `outer()` finished executing, the `inner()` function still **remembers** `count`.  
That’s a closure!

---

# 🔹 Why Closures are Useful?

1. **Data privacy** (variables hidden from outside)
    
2. **Stateful functions** (functions that “remember” things)
    
3. **Callbacks & Event Listeners**
    
4. **Module pattern** (imitating private methods in JS)
    

---

# 🔹 10 Problems on Closures (with Solutions)

---

### **Problem 1: Counter Function**

Create a function that counts how many times it has been called.

```javascript
function createCounter() {
  let count = 0;

  return function() {
    count++;
    return count;
  };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
```

---

### **Problem 2: Private Variable**

Make a variable private so it cannot be accessed directly.

```javascript
function secretHolder(secret) {
  return {
    getSecret: function() {
      return secret;
    },
    setSecret: function(newSecret) {
      secret = newSecret;
    }
  };
}

const holder = secretHolder("abc123");
console.log(holder.getSecret()); // abc123
holder.setSecret("newSecret");
console.log(holder.getSecret()); // newSecret
```

---

### **Problem 3: Multiplication Factory**

Make a function that returns another function which multiplies numbers.

```javascript
function multiplier(x) {
  return function(y) {
    return x * y;
  };
}

const double = multiplier(2);
console.log(double(5)); // 10
const triple = multiplier(3);
console.log(triple(5)); // 15
```

---

### **Problem 4: Remember Me**

Create a function that remembers a name.

```javascript
function rememberName(name) {
  return function() {
    return "Hello, " + name;
  };
}

const greetAmit = rememberName("Amit");
console.log(greetAmit()); // Hello, Amit
```

---

### **Problem 5: Event Listener with Closure**

Closures allow us to remember data inside event listeners.

```javascript
function attachEvent() {
  let count = 0;
  document.getElementById("btn").addEventListener("click", function() {
    count++;
    console.log("Button clicked " + count + " times");
  });
}
attachEvent();
```

---

### **Problem 6: Delay Logger**

Print numbers 1 to 5 with `setTimeout`.

❌ Common mistake:

```javascript
for (var i = 1; i <= 5; i++) {
  setTimeout(() => console.log(i), 1000);
}
// Prints 6 five times
```

✅ Solution using closure:

```javascript
for (var i = 1; i <= 5; i++) {
  (function(n) {
    setTimeout(() => console.log(n), 1000 * n);
  })(i);
}
// Prints 1, 2, 3, 4, 5
```

---

### **Problem 7: Create ID Generator**

Every time you call, you get a new ID.

```javascript
function idGenerator() {
  let id = 0;
  return function() {
    id++;
    return "ID-" + id;
  };
}

const generate = idGenerator();
console.log(generate()); // ID-1
console.log(generate()); // ID-2
```

---

### **Problem 8: Only Once Function**

Function should only run once.

```javascript
function once(fn) {
  let called = false;
  let result;

  return function(...args) {
    if (!called) {
      result = fn(...args);
      called = true;
    }
    return result;
  };
}

const sayHello = once(() => "Hello");
console.log(sayHello()); // Hello
console.log(sayHello()); // Hello (still)
```

---

### **Problem 9: Caching / Memoization**

Closures help cache results.

```javascript
function memoize(fn) {
  let cache = {};

  return function(x) {
    if (cache[x] !== undefined) {
      return "From cache: " + cache[x];
    }
    let result = fn(x);
    cache[x] = result;
    return "Calculated: " + result;
  };
}

const square = memoize(n => n * n);
console.log(square(4)); // Calculated: 16
console.log(square(4)); // From cache: 16
```

---

### **Problem 10: Module Pattern**

Closures help simulate private methods.

```javascript
const BankAccount = (function() {
  let balance = 0;

  return {
    deposit: function(amount) {
      balance += amount;
      return balance;
    },
    withdraw: function(amount) {
      if (amount <= balance) {
        balance -= amount;
        return balance;
      }
      return "Insufficient funds";
    },
    getBalance: function() {
      return balance;
    }
  };
})();

console.log(BankAccount.deposit(100)); // 100
console.log(BankAccount.withdraw(30)); // 70
console.log(BankAccount.getBalance()); // 70
```
