Injection - sorting it out
A first example of passing functions as parameters is provided by the Array.prototype.sort() method. If you have an array of strings, and you want to sort it, you can just use something like the following code. For example, to alphabetically sort an array with the colors of the rainbow:
var colors = [
"violet",
"indigo",
"blue",
"green",
"yellow",
"orange",
"red"
];
colors.sort();
console.log(colors);
// ["blue", "green", "indigo", "orange", "red", "violet", "yellow"]
Note that we didn't have to provide any parameters to the .sort() call, but the array got sorted perfectly well. By default, this method sorts strings according to their ASCII internal representation. So, if you use this method to sort an array of numbers, it will fail, since it will decide that 20 must be between 100 and 3, because 100 precedes 20 --taken as strings!-- and the latter precedes 3... this needs fixing! The code below shows the problem.
var someNumbers = [3, 20, 100];
someNumbers.sort();
console.log(someNumbers);
// [100, 20, 3]
But, let's forget numbers for a while, and keep to sorting strings. We want to ask ourselves: what would happen if we wanted to sort some Spanish words (palabras) -- but following the appropriate locale rules? We would be sorting strings, but results wouldn't be correct, anyhow:
var palabras = ["ñandú", "oasis", "mano", "natural", "mítico", "musical"];
palabras.sort();
console.log(palabras);
// ["mano", "musical", "mítico", "natural", "oasis", "ñandú"] -- wrong result!
For language or biology buffs, "ñandú" in English is "rhea", a running bird somewhat similar to ostriches. There aren't many Spanish words beginning with "ñ", and we happen to have these birds in my country, Uruguay, so that's the reason for the odd word!
Oops! In Spanish, "ñ" comes between "n" and "o", but "ñandú" got sorted at the end. Also, "mítico" (in English, "mythical"; note the accented "i") should appear between "mano" and "musical", because the tilde should be ignored. The appropriate way of solving this is by providing a comparison function to sort(). In this case, we can use the localeCompare() method:
palabras.sort((a, b) => a.localeCompare(b, "es"));
console.log(palabras);
// ["mano", "mítico", "musical", "natural", "ñandú", "oasis"]
The a.localeCompare(b,"es") call compares strings a and b, and returns a negative value if a should precede b, a positive value if a should follow b, and 0 if a and b are the same -- but, according to Spanish ("es") ordering rules. Now things are right! And the code could become clearer by introducing a new function, with an understandable name:
const spanishComparison = (a, b) => a.localeCompare(b, "es");
palabras.sort(spanishComparison);
// sorts the palabras array according to Spanish rules:
// ["mano", "mítico", "musical", "natural", "ñandú", "oasis"]
In upcoming chapters we will be discussing how FP lets you write code in a more declarative fashion, producing more understandable code, and this sort of small change helps: readers of the code, when they get to the sort, will immediately deduce what is being done, even if the comment wasn't present.
This way of changing the way the sort() function works by injecting different comparison functions, is actually a case of the Strategy design pattern. We'll be seeing more about this in Chapter 11, Implementing Design Patterns - The Functional Way.
Providing a sort function as a parameter (in a very FP way!) can also help with several other problems, such as:
- sort() only works with strings. If you want to sort numbers (as we tried to do earlier above) you have to provide a function that will compare numerically. For example, you would write something like myNumbers.sort((a,b) => a-b)
- If you want to sort objects by a given attribute, you will use a function that compares to it. For example, you could sort people by age with something along the lines of myPeople.sort((a,b) => a.age - b.age)
For more on the localeCompare() possibilities, see https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/localeCompare. You can specify which locale rules to apply, in which order to place upper/lower case letters, whether to ignore punctuation and much more -- but be careful; not all browsers may support the needed extra parameters.
This is a simple example, that you have probably used before -- but it's an FP pattern, after all. Let's move on to an even more common usage of functions as parameters, when you do Ajax calls.