Guide
Video
Resources
Sections:

Introduction

First-class Functions

pluralize

map

forEach

filterArray

eitherFilter

eitherCallback

reduce

intersection

union

objOfMatches

arrToObj

multiMap

majority

prioritize

countBy

groupBy

goodKeys

Conclusion

Sections:

First-Class Functions

Variables Can Be Functions

JavaScript is one of many programming languages with first-class functions, which means that functions can be treated like any other variable. You can assign a function to be the value of a variable, a function can be the return value of another function, and most importantly: you can pass a function as an argument into another function. This is the central idea behind callbacks and higher-order functions.

It's not immediately obvious that functions in JavaScript are the same as other variables, since the traditional syntax for declaring a function can look a lot different from the syntax for declaring other variables.

Your average variable in JavaScript can be declared with the keyword const.
const foo = 42;
const bar = 'Hello, world!';
If this variable needs to be reassigned or redeclared at any point after declaration, then it should be declared with the keyword let instead.
let foo = false;
foo = true;
Functions on the other hand are traditionally declared using the function keyword. There's no assignment operator (=) to be found.
function foo() {
  return 'Hello, world!';
}
In the code snippet above, foo is a variable just as it was in the prior examples. In this case, foo's value is the function object itself. To see what we mean, let's first console.log the value of a normal variable.
const foo = 42;
console.log(foo); // -> 42
We've initialized a variable with the label foo and assigned it a value of the number 42. When we console.log(foo), we see that its value is 42, as expected.

Now, let's take our function example from before.
function foo() {
  return 'Hello, world!';
}
If we console.log the evaluated result of invoking this function, the output will be straightforward:
console.log(foo()); // -> 'Hello, world!'
But instead of invoking this function like foo(), let's just log the value of foo itself.
console.log(foo);
/*
logs the following:
function foo() {
  return 'Hello, world!';
}
*/
When a function is declared with the function keyword, it creates a variable with the label you gave that function. The value assigned to this label is the function object you declared. So in our example, we've declared a function with the label foo. When we console.log the value of the variable foo, we see that this value is the function object foo.

The exact output from this console.log may differ depending on your JavaScript runtime environment, but the process is the same. For example, your output may not have any line breaks.
console.log(foo); // -> function foo() { return 'Hello, world!'; }
Alternatively, your output may even look like this:
console.log(foo); // -> [Function: foo]
The outcome is the same: foo is a variable with the value of the function object that we wrote. To see this object, we could invoke the toString() function method on foo and log the result.
console.log(foo.toString());
/*
logs the following:
'function foo() {
  return 'Hello, world!';
}'
*/
With functions being nothing more than special objects, they don't just have methods like toString(); they have other properties as well. Much like an array's array.length, functions have properties such as function.name. Let's look at foo's name property.
console.log(foo.name); // -> 'foo'
So, as each console.log has demonstrated, variables in JavaScript can take many forms. A variable could be a number, a variable could be a boolean, or a variable could be a function, among other possibilities. You can pass functions around from one part of your code to another just as easily as you can with any other variable. Keeping this in mind, callbacks and higher-order functions are much easier to reason about.

Function Syntax

With the myriad of functions you're going to encounter in this guide and beyond, it's important to recognize the different forms that a function can take. So far, the functions we've looked at have used function declaration syntax. Here are some examples of functions declared this way:
function divideByTwo(number) {
  return number / 2;
}
console.log(divideByTwo(4)); // -> 2

function concatWithS(string) {
  return `${string}s`;
}
console.log(concatWithS('apple')); // -> 'apples'

function addNumbers(number1, number2) {
  return number1 + number2;
}
console.log(addNumbers(1, 2)); // -> 3
The purpose of these functions and their return values are straightforward. We see from its function definition that divideByTwo has one parameter: number. Inside its function body, divideByTwo uses the division operator to return a value equivalent to number divided by two. Similarly, concatWithS and addNumbers use a template literal and the addition operator respectively in order to return their desired output values based off of the data passed in as input.

From these examples, we can derive a simple function declaration template for illustration purposes:
// function declaration
function name(parameter1, parameter2) {
  return returnValue;
}

// function invocation
name(argument1, argument2);
All function declarations follow this format. First comes the function keyword, followed by the name of the function. The function's name is immediately followed by a list of its input parameters. The example in our template has two, but functions can be defined with zero, one, or any other number of parameters. After this comes the opening curly brace of the function's body. Between that and the closing curly brace, we can include a list of statements for our function to execute. In most cases, our list of statements will end with a return statement: the return keyword followed by any value that we wish to return. The return value will often be influenced by the value of the function's inputs.

Besides defining a function with a traditional declaration, the bottom of our template shows us an invocation of that function. A function is invoked when its name is used and followed by parens, in any context other than the initial function definition. Within those parens, we include any arguments we wish to pass into our function as input. These arguments are imported as the value of the function's parameters, and then the statements inside the function's body are executed.

In our example, argument1 will be imported as the value of parameter1, and argument2 will likewise be matched to parameter2. If these parameters were used inside the function body, then for that specific call those parameters would have the value of those arguments within that body. Once the function reaches and evaluates its return statement, the code stops running and the return value will be passed back to the initial context from which the function was called. So, name(argument1, argument2) has an evaluated result of returnValue.

Looking back at our functions divideByTwo, concatWithS, and addNumbers as well as their invocations, it's clear to see how the code runs through the lens of our function declaration template. However, what if the functions looked like this instead?
const divideByTwo = function (number) {
  return number / 2;
};
console.log(divideByTwo(4)); // -> 2

const concatWitihS = function (string) {
  return `${string}s`;
};
console.log(concatWithS('apple')); // -> 'apples'

const addNumbers = function (number1, number2) {
  return number1 + number2;
};
console.log(addNumbers(1, 2)); // -> 3
These are not function declarations, these are function expressions. More specifically, in each of these examples we have declared a constant and assigned it the value of an anonymous function expression. It's important to distinguish between both sides of the assignment operator when it comes to initializing variables with function expressions as values. Much like the 42 in const foo = 42, the right side of this assignment in the examples above is just a value. Just like 42 by itself is not declaring anything, the function expression by itself is not declaring anything either, unlike a function declaration. That is why there is a declaration happening on the left, using the const keyword. Like any other value, a function expression doesn't always have to be assigned to a label using const or let. It can also be passed into a function as an argument, or returned from a function as a return value.

You may have also noticed the anonymity of these functions; there is no name following the function keyword. While function declarations do need a name, it's optional for function expressions. In the event that no name is used but the functixon is assigned to a variable, then the name can be inferred from the variable's label. So in the above example, divideByTwo.name === 'divideByTwo', despite the function expression itself not having a name. However, functions used in function expressions need not always be anonymous, so this is also valid code:
// named function expression assigned to constant
const divideByTwo = function divider(number) {
  return number / 2;
};

console.log(divideByTwo.name) // -> divider
Let's use all of this knowledge to come up with a template for function expressions.
// anonymous function expression assigned to constant
const name = function (parameter1, parameter2) {
  return returnValue;
};

// function invocation
name(argument1, argument2);
You will encounter function expressions, both anonymous and named, throughout this guide and beyond. You can think of them as being values that are functions; much like 42 is a value that is a number, and "Hello, world!" is a value that is a string. Like these other values, function expressions will often be assigned to variables using let or const, and they can be passed into other functions and returned from other functions as well.

Besides function declarations and traditional function expressions, there is another type of syntax you'll commonly see when it comes to writing functions: arrow function expressions. This is the most commonly used syntax that you'll see in this guide:
const divideByTwo = (number) => number / 2;
console.log(divideByTwo(4)); // -> 2

const concatWithS = (string) => `${string}s`;
console.log(concatWithS('apple')); // -> 'apples'

const addNumbers = (number1, number2) => number1 + number2;
console.log(addNumbers(1, 2)); // -> 3
In each example above, we have declared a constant and assigned it the value of an arrow function expression. There seems to be quite a lot missing at first when compared to a traditional function expression: the function keyword, the curly braces, and the return keyword are nowhere to be found. However, it's important to note that an arrow function is just a special kind of anonymous function expression, with different syntax. The list of parameters is still there, and the return value is being returned implicitly.

All of the example functions we've been using so far have only had one statement within their body, as opposed to a longer list. If your function is like those examples and contains just a single expression, then arrow functions allow you to forgo the curly braces for the body, and leave out the return keyword. The expression after the arrow will be returned automatically; this is called implicit return.
const foo = () => 'Hello, world!';

console.log(foo()); // -> 'Hello, world!'
// the string was returned implicitly
However, many functions will have multiple statements to execute before a return is reached. If there is more than one statement within your function, then your arrow function will need curly braces to contain those statements. Similarly, if your code contains something that is not an expression that can be returned, such as an if statement or a variable declaration, then curly braces are needed for that situation as well. The return will not be implicit if curly braces are present, so the return keyword must be used if you wish to return a value, just like any other function with curly braces.
// curly braces are needed for this function 
const game = (score) => {
  if (score >= 100) return 'You won!';
  else if (score >= 50) return 'Almost there...';
  else return 'Try again next time!';
};
It's also worth noting that when an arrow function has exactly one parameter, the parens around that parameter can be omitted. For consistency, the code in this guide will always use parens for an arrow function's parameters, but it's important to know that both of the following functions work the same way:
const affirmation = name => `Great work, ${name}!`;
const affirmation2 = (name) => `You've got this, ${name}!`;
With all of this in mind, let's look at a template for writing arrow function expressions. We'll also include the templates for the previous syntax as well, so you can easily see the differences and similarities.
// arrow function expression assigned to a constant
const name = (parameter1, parameter2) => returnValue;

// anonymous function expression assigned to constant
const name = function (parameter1, parameter2) {
return returnValue;
};

// function declaration
function name(parameter1, parameter2) {
return returnValue;
}

// function invocation
name(argument1, argument2);
As you can see, these functions differ in appearance, but they're all invoked the same way. There are differences under the hood when it comes to functions written using these different methods; in some situations one kind of function is preferable over another, and in other situations certain kinds of functions should be avoided altogether. However, within the scope of this guide, all of the aforementioned function syntax will appear interchangeably, so make sure you're comfortable recognizing and writing function declarations, function expressions, and arrow function expressions. With this knowledge, you'll always be able to analyze your code and know exactly what each line is doing at any given time.

Callback Structure

Now that we're familiar with the nature of functions and the various syntax that we'll encounter, let's look at how this all fits into this guide's main focus: callbacks and higher-order functions. We know that a variable can be a function, and that variables can be passed into functions as arguments. So what happens when you pass a function into a different function as an argument? In order to see this in action, let's start with an example problem that calls for a higher-order function:
Write a function called thrice that accepts two arguments: a callback function, and a value. Your thrice function should invoke the callback three times, following this logic:

On the first invocation, thrice should pass its input value into the callback as an argument.

On the second invocation of the callback, thrice should pass in the result of the first invocation.

On the third invocation, thrice should pass in the result of the second invocation.

Finally, after these three function calls, thrice should return the result of the third invocation.

Example 1:
Input
callback = (number) => number / 2
value = 8
Output
thrice(callback, value) === 1

Example 2:
Input
callback = (string) => `${string}s`
value = 'cat'
Output
thrice(callback, value) === 'catsss'
This challenge's prompt is asking us to implement a function that simulates running a callback three times. Using our example functions from earlier, passing in divideByTwo and the number 8 should give us a result of 1, which is what happens if you divide 8 by 2 three times. Similarly, passing in concatWithS and the string 'cat' should give us 'catsss', since that's what happens when you add an 's' to 'cat' three times. Let's start by writing out our function body:
const thrice = (callback, value) => {
  // TODO
};
We now have a function that accepts the parameters specified in the prompt. Next, let's implement the core idea: repeating an action three times. The most straightforward method for this is a simple for loop.
const thrice = (callback, value) => {
  for (let i = 0; i < 3; i += 1) {
    // TODO
  }
};
Now, let's tackle the trickier part. On each iteration, we're going to invoke the callback. The argument that's passed into this callback should first have a value equal to the one passed into thrice. Before our loop starts, let's initialize a variable with this value, called result. Then, within the loop, we'll pass that variable into the callback, and save the output of that invocation to a new variable called newResult.
const thrice = (callback, value) => {
  let result = value;

  for (let i = 0; i < 3; i += 1) {
    const newResult = callback(result);
  }
};
Now we have a loop that invokes the callback, passing in the result variable each time. This works on our first iteration, but we know that on the next iteration, the value of newResult should be passed into our callback. So, let's just give that value to our result variable before moving to that second iteration:
const thrice = (callback, value) => {
  let result = value;

  for (let i = 0; i < 3; i += 1) {
    const newResult = callback(result);
    result = newResult;
  }
};
Now, in the second iteration of our loop, result has the value of the output of the first callback invocation. We pass this value into the callback, and save it to newResult. We then use the value of newResult to overwrite result once again, before moving to the third and final iteration.

On the last iteration, result has the value of the output of the second invocation, so we pass this into the callback and save it to newResult once again. One final time, we overwrite result with the value of newResult, and then the loop concludes.

Now, outside of the loop, result is left with the value of the third invocation of the callback. Referring back to our prompt, this is the value we're supposed to return. So, as a final step, let's add that return statement and then run some test cases.
const thrice = (callback, value) => {
  let result = value;

  for (let i = 0; i < 3; i += 1) {
    const newResult = callback(result);
    result = newResult;
  }

  return result;
};

const divideByTwo = (number) => number / 2;
const concatWithS = (string) => `${string}s`;

console.log(thrice(divideByTwo, 8)); // -> 1
console.log(thrice(concatWithS, 'cat')); // -> catsss
We've now finished implementing our function. A higher-order function satisfies at least one of two criteria: accepting a function as an argument, or returning a function as its return value. Like most of the solutions in this guide, thrice fits that first criteria.

Now that we have a higher-order function, let's take a closer look at callback functions by examining the test cases and the way thrice is invoked.

In the code snippet above, we have defined our previously-discussed divideByTwo and concatWithS functions. On each invocation of thrice, we pass one of those functions in as the first argument. This means that within the context of those invocations, divideByTwo and concatWithS are callback functions, meaning they have been passed into another function as an argument and then invoked inside that function.

One thing that's important to note is that we invoke thrice, the callback we pass in is a function object, not a function invocation. There are no parens after the callback's label, because we are not invoking it; we want to pass in the function itself as opposed to the evaluated result of invoking that function.

Let's walk through exactly how our code runs, using the first test case as an example. First, thrice is invoked. divideByTwo is imported as the value of the parameter callback, and 8 is imported as the value of the parameter value. We then initialize our result variable with value, and enter our for loop. Within this for loop, we invoke callback. This means that we are invoking the function object that was passed in, using result as the argument.

This next part is the key to understanding higher-order functions: whenever a function is invoked, a new execution context is opened. Look at the line as a whole:
const newResult = callback(result);
Before we can actually assign a value to newResult, we have to find the value to assign, by evaluating callback(result). This means that JavaScript will pause execution of the current function thrice, and begin executing callback(result), which we know to be divByTwo(8).

We can now refer to the definition of the currently executing function, divByTwo, where we see that 8 is imported as the value of the argument number. We evaluate 8 divided by two, and this result of 4 is implicitly returned. When the return keyword is reached in a function, it returns to the previous execution context, in the exact site that the function was called. The value after the return keyword is brought back to that previous context, where it can then be used. So, divByTwo(8) has returned 4 to the previous context, where it is used as the evaluated result of the invocation of divByTwo(8). It is now equivalent to this:
const newResult = 8;
From there, this process is repeated; two more calls to divByTwo are made, returning the values of 2 and 1 respectively. And each time, JavaScript pauses the execution of thrice, opens a new execution context to evaluate the function call divByTwo(result), and then returns that evaluated result to the previous context's call site in thrice.

This process of opening a new context happens every single time a function is invoked, whether that's within the global context of our test case invoking thrice, or within the local context of thrice invoking divByTwo. As we look at more and more higher-order functions and callbacks, it helps to be able to follow the thread of execution from one context to another.

One final note: function expressions will often be passed directly into a function as a callback argument, without even being saved to a variable first. For example, the following invocations of thrice would also work:
console.log(thrice((number) => number / 2, 8)); // -> 1

console.log(thrice(function(string) {
  return `${string}s`
}, 'cat')); // -> catsss
In the first example above, we have passed an arrow function expression into thrice. That's the function object that will be imported as the value as the first parameter. The second example may be a little bit less obvious since it spans multiple lines, but we've still just passed an anonymous function expression into thrice as the first argument. The entire function across those three lines is thrice's first argument, which is why it's followed by a comma separating it from the second argument, 'cat'. Recognizing when a function has been passed in as a callback even if it spans multiple lines is crucial, as this will happen often with higher-order functions.

This concludes the "First-class Functions" section, which is the basis of understanding all the following challenges in this guide. If you know that functions are just like any other value in JavaScript, if you can identify the syntax patterns that functions can take, and if you're able to effectively follow the thread of execution in a higher-order function like thrice, then you'll be able to fully grasp every single challenge in the CSX Callbacks and Higher Order functions module.