JavaScript Closures Cheatsheet
Published: 2024-05-24 04:22:50


## 1. What is a Closure?
A closure is the combination of a function bundled together (enclosed) with references to its surrounding state (the lexical environment)

## 2. Basic Example
```javascript
function outerFunction() {
    let outerVariable = 'I am outside!';

    function innerFunction() {
        console.log(outerVariable);
    }

    return innerFunction;
}

const myFunction = outerFunction();
myFunction(); // Output: I am outside!
```

## 3. Lexical Scoping
Closures work by capturing variables from their lexical environment.
```javascript
function makeCounter() {
    let count = 0;

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

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

## 4. Immediately Invoked Function Expression (IIFE)
IIFEs create closures to encapsulate variables.
```javascript
const increment = (function() {
    let counter = 0;
    return function() {
        counter++;
        return counter;
    }
})();

console.log(increment()); // 1
console.log(increment()); // 2
```

## 5. Closure with Loop (Common Pitfall)
Using `var` in a loop can lead to unexpected behavior due to function-level scope.
```javascript
for (var i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}
// Output: 3, 3, 3
```
Solution with `let`:
```javascript
for (let i = 0; i < 3; i++) {
    setTimeout(function() {
        console.log(i);
    }, 1000);
}
// Output: 0, 1, 2
```

## 6. Data Privacy
Closures can be used to emulate private variables.
```javascript
function createSecretHolder(secret) {
    let secretValue = secret;

    return {
        getSecret: function() {
            return secretValue;
        },
        setSecret: function(newSecret) {
            secretValue = newSecret;
        }
    };
}

const holder = createSecretHolder('mySecret');
console.log(holder.getSecret()); // 'mySecret'
holder.setSecret('newSecret');
console.log(holder.getSecret()); // 'newSecret'
```

## 7. Partial Application
Closures can be used for partial function application.
```javascript
function add(a) {
    return function(b) {
        return a + b;
    }
}

const addFive = add(5);
console.log(addFive(3)); // 8
```

## 8. Function Factories
Closures enable function factories.
```javascript
function multiplier(factor) {
    return function(number) {
        return number * factor;
    }
}

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

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

## 9. Module Pattern
The module pattern uses closures to create public and private methods.
```javascript
const Module = (function() {
    let privateVar = 'I am private';

    function privateMethod() {
        console.log(privateVar);
    }

    return {
        publicMethod: function() {
            privateMethod();
        }
    };
})();

Module.publicMethod(); // 'I am private'
```

## 10. Handling Asynchronous Closures
```javascript
function createCounter() {
    let count = 0;

    return {
        increment: function() {
            count++;
            return count;
        },
        getCount: function() {
            return count;
        }
    };
}

const asyncCounter = createCounter();

setTimeout(() => {
    asyncCounter.increment();
    console.log(asyncCounter.getCount()); // 1
}, 1000);
```

## 11. Closures in Event Listeners
```javascript
function setupButton() {
    let clickCount = 0;

    document.getElementById('myButton').addEventListener('click', function() {
        clickCount++;
        console.log(`Button clicked ${clickCount} times`);
    });
}

setupButton();
```

## 12. Common Use Cases
- **Encapsulation:** Protecting variables from being accessed or modified outside their intended context.
- **Callbacks:** Passing a function as an argument to be executed later.
- **Event Handlers:** Managing event-driven programming.
- **Functional Programming:** Creating higher-order functions and function factories.

## 13. Best Practices
- Minimize the use of closures for better memory management.
- Be mindful of scope and lifetime of variables.
- Use `const` or `let` instead of `var` to avoid common pitfalls with closures in loops.