DEV Community

Daniel Hintz
Daniel Hintz

Posted on • Edited on

Functions Creating Functions!

Hi there! This goes through how to do this in JavaScript. I also wrote a sister-article that goes through how to do the same thing in Ruby.

We all know what a programming function is and what it does. It encapsulates a particular behavior. For example, this function divides any number you'd like by 5.

function divideBy5(number) {
  return number / 5;
}

divideBy5(15)
  // => 3
Enter fullscreen mode Exit fullscreen mode

But in life, we often see different variations of a complex behavior, and this is a situation we see a lot in programming as well. For example, imagine we wanted to add some complexity to the above function so that it only divides numbers that are cleanly divisible by 5. We could easily do this:

function divideBy5(number) {
  if(number % 5 === 0) {
    return number / 5;
  }
  return `${number} is not divisible by 5!`;
}

divideBy5(15)
  // => 3
divideBy5(7)
  // => "7 is not divisible by 5!"
Enter fullscreen mode Exit fullscreen mode

But we might need to similarly divide by other numbers later on in our program. We could write a new function for each number, but that would be a pain. Instead, let's create a function which in turn creates other functions!

To do this, we'll create a wrapper function, this is where we'll set up our flexibility by passing an argument. This argument will represent the variation in the behavior; in our simple case, it's a specific divisor. We want to be able to divide by 5, or 8, or 100, or whatever else our hearts desire, so we'll call this argument divisor.

function DivideBy(divisor) {
  // the rest of the function will go here.
}
Enter fullscreen mode Exit fullscreen mode

Now, we know that the output of the function needs to be a different function, so our return value will need to be a function declaration. There's no need for this inner function to have a name, so we'll create an anonymous function that takes in an argument - this will be the number that we want evaluated (15 in our first example).

function DivideBy(divisor) {
  return function(number) {
    // the rest of the function will go here
  }
}
Enter fullscreen mode Exit fullscreen mode

Now, we can add in our main functionality, which was defined in our divideBy5() example, but we now get to parameterize BOTH the numerator that we want evaluated, AND the divisor.

function DivideBy(divisor) {
  return function(number) {
    if(number % divisor === 0) {
      return number / divisor;
    }
    return `${number} is not divisible by ${divisor}!`;
  }
}
Enter fullscreen mode Exit fullscreen mode

Great! Now if we call DivideBy(5), we get:

ƒ (number) {
    if(number % divisor === 0) {
      return number / divisor;
    }
    return `${number} is not divisible by ${divisor}!`;
  }
Enter fullscreen mode Exit fullscreen mode

...I know what you're thinking - "What's this? What are we supposed to do with it?" And the answer is deceptively simple: just name it! That output is a function which is asking for a number to divide by the divisor that we just passed in (5). So we create a function expression so we can reference it later: const DivideByFive = DivideBy(5) and we now have the same function as our divideBy5(number) function from before. We can call it like so:

DivideByFive(15)
  // => 3
Enter fullscreen mode Exit fullscreen mode

The benefit of this pattern is that we can now assign this behavior to any divisor/number variation. As the complexity of the behavior goes up, this becomes more and more useful.

Here's the full code:

function DivideBy(divisor) {
  return function(number) {
    if(number % divisor === 0) {
      return number / divisor;
    }
    return `${number} is not divisible by ${divisor}!`;
  }
}

const DivideByFive = DivideBy(5);
  // => undefined
const divBy8 = DivideBy(8);
  // => undefined
const divideNumberBy100 = DivideBy(100);
  // => undefined

DivideByFive(15)
  // => 3

DivideByFive(8)
  // => "8 is not divisible by 5!"

divideNumberBy100(500)
  // => 5
Enter fullscreen mode Exit fullscreen mode

Top comments (0)