Learn First-Class Functions in JavaScript

nas5w

Nick Scialli (he/him)

Posted on July 2, 2020

Learn First-Class Functions in JavaScript

Please give this post a 💓, 🦄, or 🔖 if it you enjoy it!


JavaScript has first-class functions. This means functions can be treated like other values, which turns out to be incredibly important behavior to understand as you advance as a JavaScript developer. The following three bullets represent important first-class function behavior:

  • Functions can be assigned to variables
  • Functions can be passed as arguments to other functions
  • Functions can be returned from other functions

Let's explore each of these bullets using basic examples and then bring it all together at the end with a couple more complex, real-world examples!


I make other easy-to-digest tutorial content! Please consider:


Assigning Functions to Variables

Let's create a function that returns the text "Hello" and then assign that function to a variable creatively named sayHello.

const sayHello = () => {
  return 'Hello';
};

console.log(sayHello());
// "Hello"
Enter fullscreen mode Exit fullscreen mode

Pretty basic! Let's move on.

Passing a Function as an Argument

Let's take the aforementioned sayHello function and pass it as an argument to another function. This other function will say hello to a particular person.

const sayHelloToPerson = (greeter, person) => {
  return greeter() + ' ' + person;
};

console.log(sayHelloToPerson(sayHello, 'John'));
// Hello John
Enter fullscreen mode Exit fullscreen mode

A quick note on what happens when we pass the sayHello function to sayHelloToPerson: within the sayHelloToPerson function, the variable greeter will now point to the sayHello function in memory. When we call greeter(), the function is called!

Note: I'd normally use template literals in this case (i.e., return `${greeter()} ${person}`), but didn't want template literal syntax to muddy the water in this example!

Return a Function from Another Function

Maybe we don't alway want to say "Hello", but rather want the choice of creating any number of different types of greeters. Let's use a function that lets us create greeter functions.

const greeterMaker = greeting => {
  return person => {
    return greeting + ' ' + person;
  };
};

const sayHelloToPerson = greeterMaker('Hello');
const sayHowdyToPerson = greeterMaker('Howdy');

console.log(sayHelloToPerson('Joanne'));
// "Hello Joanne"

console.log(sayHowdyToPerson('Joanne'));
// "Howdy Joanne"
Enter fullscreen mode Exit fullscreen mode

Our greeterMaker is a function that creates functions! Pretty nifty, right?

Some Fun, Real-World Use Cases

Now that we checked out the basics of first-class functions, let's look at some real-world use cases!

Object Validation

Perhaps you have a bunch of criteria that an object (e.g., new user information) needs to pass to be considered "valid." Let's create a function that iterates over all our criteria and returns whether the object is valid or not.

const usernameLongEnough = obj => {
  return obj.username.length >= 5;
};

const passwordsMatch = obj => {
  return obj.password === obj.confirmPassword;
};

const objectIsValid = (obj, ...funcs) => {
  for (let i = 0; i < funcs.length; i++) {
    if (funcs[i](obj) === false) {
      return false;
    }
  }

  return true;
};

const obj1 = {
  username: 'abc123',
  password: 'foobar',
  confirmPassword: 'foobar',
};

const obj1Valid = objectIsValid(obj1, usernameLongEnough, passwordsMatch);
console.log(obj1Valid);
// true

const obj2 = {
  username: 'joe555',
  password: 'foobar',
  confirmPassword: 'oops',
};

const obj2Valid = objectIsValid(obj2, usernameLongEnough, passwordsMatch);
console.log(obj2Valid);
// false
Enter fullscreen mode Exit fullscreen mode

If you're relatively new to JavaScript, it might take you several read-throughs to understand what's going on, but trust me, the payoff is great once you understand!

Note: If you're unfamiliar with the rest operator (...), this simply allows all remaining arguments provided to the function to be put into an array by the specified name.

API Key Closure

Perhaps we have a situation where we want to connect to an API using an API key. We could add this key on every request, or, we could create a function that takes an API key parameter and returns functions that contain the API key with each request.

Important: Don't put secret API keys in front-end code. Instead, imagine the following code is in a node-based back-end.

const apiConnect = apiKey => {
  const getData = route => {
    return axios.get(`${route}?key=${apiKey}`);
  };

  const postData = (route, params) => {
    return axios.post(route, {
      body: JSON.stringify(params),
      headers: {
        Authorization: `Bearer ${apiKey}`,
      },
    });
  };

  return { getData, postData };
};

const api = apiConnect('my-secret-key');

// No need to include the apiKey anymore
api.getData('http://www.example.com/get-endpoint');
api.postData('http://www.example.com/post-endpoint', { name: 'Joe' });
Enter fullscreen mode Exit fullscreen mode

Conclusion

And there you have it! Hopefully by now you see that functions in JavaScript are truly first-class and how important functions can be to your JavaScript development career. I recommend practicing all sorts of ways to use functions in your code!

💖 💪 🙅 🚩
nas5w
Nick Scialli (he/him)

Posted on July 2, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related