The Anatomy of a JavaScript function, part 2

Let's learn how to generalize functions in JS!

By: Ajdin Imsirovic 18 October 2019

This is the second post in the series of posts titled “The Anatomy of a JavaScript function”.

Three clear glasses with juice Photo by Kobby Mendez on Unsplash.com

If you are brand new to functions in JavaScript, I warmly recommend reading part 1 first.

Let’s quickly revise what we’ve learned:

Javascript functions are like machines.

We can define them - i.e “build the machine”.

We can call them - i.e “run the machine”.

We can define what inputs (“raw materials”) the machine will take - i.e we specify function parameters.

We can give the actual inputs to the machine when we run it - i.e we call our function, and we pass in arguments it will use.

In part 1, we’ve seen an example of a Bottle Capper machine and then we wrote a JavaScript function to imitate that behavior.

When we built the Bottle capper machine in the form of the bottleCapper function, we gave it two parameters: a bottle and a cap.

function bottleCapper(bottle, cap) {
  return bottle + cap;
}

Now we realize that we want to build another machine. This one will staple two pieces of paper together, so we’ll call it paperStapler.

function paperStapler(firstPiece, secondPiece) {
  return firstPiece + secondPiece
}

And now we can run it too, just like this:

paperStapler("Page 1", "Page 2")

Great! We’ve just built and ran our new machine!

Soon enough, if we keep going like this, we might have a full warehouse of those things!   We just think of a simple machine, and poof - we build it, just like that.

Things can’t possibly get better than this, right?

Or can they?

Truth is, if we compare our bottleCapper and our paperStapler, we’ll see they’re doing almost the exact same thing.

Even their structure is almost the same. Generally, we could look at it like this:

function machineName(something1, something2) {
  return something1 + something2
}

Taking things even further, let’s change a rather non-descript machineName function name and call it concatenateArgs.

“Concatenate” is a fancy way of saying “put them together”, and “Args” is just an abbreviation of “Arguments”.

We can make our function name even shorter, and call it concatArgs.

Instead of something1 and something2, let’s give it a more generic a and b.

Now we have our updated function definition:

function concatArgs(a, b) {
  return a + b
}

We’ve just built a magical machine! We no longer have to specify if it’s a Bottle capper or a Paper stapler - whatever two things we give it, it will put them together.

Thus, instead of filling up our warehouse with a bunch of machines that generally do the same thing, we’ve just built a single one that’s gonna do all the work. Pretty cool stuff!

Generalizing functions

Hopefully you’ve caught me writing the word “generally” in the previous section twice. It was a hint at the formal name for what we did in the previous section: We took the bottleCapper and the paperStapler functions and we generalized them into concatArgs.

Generalizing makes our functions applicable to more situations.

Let’s look at another example to see this in practice.

Let’s say we want to allow a user to give us a number, and we’ll tell our user if that number is divisible by 2.

Of course, this is a trivial example, but our focus here is on function generalization; our focus is not on building complex functions.

We’ll keep things even simpler and use ES5 syntax:

var divisibleByTwo = function() {
  var num = Number(prompt("Enter a number"))
  var testResult = num % 2;
  if (testResult == 0) {
    alert ("This number IS divisible by 2");
  } 
  if (testResult != 0) {
    alert ("This number ISN'T divisible by 2");
  }
}

In the above function, we’re keeping things as simple as possible:

  • On line 1, we start to define our function
  • On line 2, we prompt the user for an answer. Since that answer is a string, we convert it to a number using the native Number() function
  • On line 3, we declare the testResult variable; we also store the result of num % 2 inside of it. The % is the modulus operator, and returns the remainder of division. If our number is divisible by 2, there will be no remainder - i.e the remainder of such division is zero.
  • On lines 4, 5, and 6, we test if the value stored in testResult is indeed a zero. If it is, we’ll alert the message: This number IS divisible by 2.
  • On lines 7, 8, and 9, we test if the value stored in testResult is not a zero. This means that our division has a remainder, such as if we divided 3 with 2, or 5 with 2, or 7 with 2, etc. If this if statement’s condition is satisfied, we’ll alert the message: This number ISN’T divisible by 2.

Let’s now imagine that we need to check if user input is divisible by 3.

We could write a similar function to the one we just saw:

var divisibleByThree = function() {
  var num = Number(prompt("Enter a number"))
  var testResult = num % 3;
  if (testResult == 0) {
    alert ("This number IS divisible by 3");
  } 
  if (testResult != 0) {
    alert ("This number ISN'T divisible by 3");
  }
}

This function, just like the previous one, works perfectly.

But how do we make a function that will check if a number is divisible by any other number, without remainder? Do we write an infinite number of functions, for each specific number?

Of course not. That would be silly.

Instead, we write a generalized divisibleByX function, like this:

var divisibleByX = function() {
  var testedNumber = Number(prompt("Enter the num to be tested"));
  var x = Number(prompt("Enter the num that tests"));
  var testResult = testedNumber % x;
  if (testResult == 0) {
    alert ("This number IS divisible by " + x);
  } 
  if (testResult != 0) {
    alert ("This number ISN'T divisible by " + x);
  }
}

Now we can run our function, and we’ll be asked two questions:

  1. Enter the num to be tested - I’ve typed in 15.
  2. Enter the num that tests - I’ve typed in 5.

Once we give these two answers, we’ll get back the following message:

This number IS divisible by 5.

If we give a different answer, such as 16 and 5, the message will be:

This number ISN’T divisible by 5.

Great! We’ve just learned how to generalize functions in JavaScript.

This wraps up part 2 of the Anatomy of a JavaScript function article series.

In part 3, we’ll learn about differences between ES5 and ES6 functions.

Feel free to check out my work here: