- Functions Are Values
- Generalizing With Higher-Order Functions
- Passing Functions As Arguments
- Exercises
JavaScript has first-class functions. This means that functions are a value like any other value: 5
, 'apples'
, true
, etc. They can be assigned to variables and passed to other functions.
Consider the following snippet:
function isPositive(num) {
return num > 0;
}
let copyOfIsPositive = isPositive;
copyOfIsPositive(-10); // => false
copyOfIsPositive(0); // => true
copyOfIsPositive(10); // => true
We we create a new variable called copyOfIsPositive
whose value is the function isPositive
. We can call copyOfIsPositive(num)
and JavaScript will know to call isPositive
.
A higher-order function is a function that accepts another function as an argument. Let's see what we can do with this feature.
Here are three functions that take a list of numbers and count how many elements match a particular condition. Notice that the code in each example is almost identical.
-
countPositive(array)
returns the count of positive numbers inarray
:function isPositive(num) { return num > 0; } function countPositive(array) { let total = 0; for(let item of array) { if (isPositive(item)) { total += 1; } } return total; }
-
countEven(array)
returns the count of even numbers inarray
:function isEven(num) { return num % 2 === 0; } function countEven(array) { let total = 0; for(let item of array) { if (isEven(item)) { total += 1; } } return total; }
-
countPrimes(array)
returns the count of prime numbers inarray
, assuming we have a working functionisPrime
defined elsewhere:function countPrimes(array) { let total = 0; for(let item of array) { if (isPrime(item)) { total += 1; } } return total; }
The code for each function is very similar. The only part that is the logic we use to decide whether to count a particular element or not: if (someCondition(item)) { ... }
.
On top of that, someCondition
is the only part of each function that even cares whether the elements are numbers or not. Say we defined isNotEmpty(string)
that tells us whether a string was empty or not, like so:
function isNotEmpty(string) {
return string !== '';
}
If we replaced someCondition(item)
with isNotEmpty(item)
then we'd have a function that counted the number of non-empty strings in an array.
Consider the following, where isPositive
, isEven
, and isPrime
are defined elsewhere:
function count(array, someCondition) {
let total = 0;
for(let item of array) {
if (someCondition(item)) {
total += 1;
}
}
return total;
}
let numbers = [-1, 0, 1, 2, 3, 4, 5, 6];
count(numbers, isPositive); // => 6
count(numbers, isEven); // => 4
count(numbers, isPrime); // => 3
Because functions are values like any other, we can pass them in as arguments. count
expects only two things:
array
is an array (but it doesn't assume anything about what it contains)someCondition
is a function that returnstrue
orfalse
for each element ofarray
This allows us to write a single count
function that works in virtually any context rather than a separate count
function for every possible context.