# Higher Order Functions in JavaScript

A higher-order function is just a function that plays with other functions. That's it.

Basically it either -

1. Take a function as input
    
2. returns a function
    

Most of the time, it does both. But even doing one of those things makes it "higher-order."

Think of it like this: regular functions work with data numbers, strings, objects. Higher-order functions work with behavior. Here's the thing that makes JavaScript special, functions are first-class citizens.

In some languages, functions are these rigid, special things. In JavaScript, a function is just another piece of data you can move around. That's why higher-order functions are so natural here we're not fighting the language, we're using it the way it was designed.

## **Let's Look at Some Basic Examples**

### **Passing a Function as an Argument**

This is probably the easiest place to start.

```javascript
function greet(name) {
  return `Hey there, ${name}!`;
}

function formalGreet(name) {
  return `Good evening, ${name}.`;
}

function saySomething(name, greetingFunction) {
  return greetingFunction(name);
}


console.log(saySomething("Sam", greet));        // "Hey there, Sam!"
console.log(saySomething("Sam", formalGreet));  // "Good evening, Sam."
```

### **Returning a Function**

```javascript
function makeMultiplier(factor) {
  return function(number) {
    return number * factor;
  };
}

const triple = makeMultiplier(3);
const double = makeMultiplier(2);

console.log(triple(5));   // 15
console.log(double(5));   // 10
```

`makeMultiplier` is like a little factory. You tell it what factor you want, and it builds you a custom function that remembers that factor.

## **The Built-In HOF**

JavaScript gives us three classics that pretty much every developer uses daily. Map, Filter, Reduce.

### Lets start with MAP

Use map when you have an array and want to turn every item into something else. Same number of items, different values.

```javascript
const prices = [10, 20, 30];
const withTax = prices.map(price => price * 1.2);

// [12, 24, 36]
```

### Next is FILTER

Use `filter` when you want to remove stuff based on a condition. You might end up with fewer items than you started with.

```javascript
const ages = [15, 22, 18, 30, 12];
const adults = ages.filter(age => age >= 18);

// [22, 18, 30]
```

### REDUCE

Use `reduce` when you want to take a whole array and collapse it into one value. Could be a sum, an object, whatever.

```javascript
const numbers = [1, 2, 3, 4];
const sum = numbers.reduce((total, num) => total + num, 0);

// 10
```

**The key thing:** don't get hung up on memorizing syntax. Focus on intent. When you look at a problem, ask yourself: "Am I transforming, selecting, or aggregating?" That tells you which tool to grab.

## **Closures: How Functions Remember Things**

When a function is created inside another function, it keeps access to all the variables from its parent even after the parent finishes. It's like the inner function carries a backpack with all the stuff it needs.

```javascript
function createCounter() {
  let count = 0;  
  
  return {
    increment: function() {
      count++;
      return count;
    },
    decrement: function() {
      count--;
      return count;
    },
    getCount: function() {
      return count;
    }
  };
}

const myCounter = createCounter();

console.log(myCounter.increment());  // 1
console.log(myCounter.increment());  // 2
console.log(myCounter.getCount());   // 2
console.log(myCounter.decrement());  // 1


console.log(myCounter.count);        // undefined (it's protected!)
```

Nothing from the outside can touch it directly, but the functions we returned can still use it. This is a classic pattern for creating configurable, stateful behavior while keeping your data safe.

```javascript
function createLogger(prefix) {
  return function(message) {
    console.log(`[${prefix}] ${message}`);
  };
}

const apiLogger = createLogger("API");
const dbLogger = createLogger("DATABASE");

apiLogger("Request received");     
dbLogger("Connection failed");     
```

## **Real-World Stuff You'll Actually Use**

### **Logging Wrappers**

Want to log how long a function takes without cluttering your business logic? here is an example

```javascript
function withTiming(fn) {
  return function(...args) {
    const start = Date.now();
    const result = fn(...args);
    const end = Date.now();
    console.log(`${fn.name} took ${end - start}ms`);
    return result;
  };
}

const slowFunction = () => {
  // ... some heavy work
};

const timedSlowFunction = withTiming(slowFunction);
timedSlowFunction();  // Logs: "slowFunction took 45ms"
```

### **Retry Logic**

APIs fail sometimes. Let's make a wrapper that tries again -

```javascript
function withRetry(fn, maxAttempts = 3) {
  return async function(...args) {
    for (let i = 1; i <= maxAttempts; i++) {
      try {
        return await fn(...args);
      } catch (error) {
        if (i === maxAttempts) throw error;
        console.log(`Attempt ${i} failed, retrying...`);
      }
    }
  };
}

const fetchWithRetry = withRetry(fetchUserData, 3);
```

Higher order functions aren't some academic CS concept they're just functions that work with other functions. JavaScript makes this easy because functions are just values we can pass around.
