Understanding Higher Order Arrow Functions

Tell us what’s happening:
So, I wanted to be sure I am understanding how these work properly. I’ve been moving in to a software developer career over the past year, and find myself constantly questioning how/why things work, and I’ve come to realize a common issue in all of my “stuck” moments is in a lack of writing out what I’m doing and what I need to do. I plan to start writing blog posts to help combat this and hopefully reinforce new concepts I’ve learned. Here is my written explanation and break down of how this is supposed to work:

 Higher order functions are simply functions that accept other functions as an argument.
(Argument being the thing that goes inside the () at the beginning of a function.)

For example, we pass a function to filter() as an argument. This function is called a 
callback. When used to filter an array, it would be called for every item in the array,
such as:

const realNumbers = [4, 5.7, -1.2, 3.14, 24, 25, 7];
const squareList = (arr) => {

	const squaredNumbers = arr.filter((num) => num > 0 && num % parseInt(num) === 0)

}

In this function, we are using filter() with the arguments of (num) and the function
(num > 0 && num % parseInt(num) === 0) to filter the array and remove decimals. We use
parseInt(num) to parse a string argument and return the number.

So the entire line reads as:
function (num) { 
	when num > 0
	and
	num remainder "num" equals 0
	do next steps
}

When the input number is greater than 0 and the remainder of the input number 
(turned in to a string to remove decimals) is equal to 0, move on to the next steps. 

So we move on to the next step of the function:

const squaredNumbers = arr.filter((num) => num > 0 && num % parseInt(num) === 0)
.map((num) => Math.pow(num, 2));

After the filter has parsed through the array and separated the numbers from decimals, it
moves on to map() over the remaining numbers, creating a new array based off the inserted
argument (num). We use Math.pow, which takes the base number(in this case the "num" argument)
and returns its exponent (2), which is simply squaring that new number.

This creates the new array of squared numbers, without the negatives and without the decimals. 

Could I get some thought/insight/clarification on this? Am I understanding it correctly?

Thanks in advance!

Your code so far


const realNumberArray = [4, 5.6, -9.8, 3.14, 42, 6, 8.34, -2];
const squareList = (arr) => {
  "use strict";
  // change code below this line
  const squaredIntegers = arr.filter((num) => num > 0 && num % parseInt(num) === 0).map((num) => Math.pow(num, 2));
  // change code above this line
  return squaredIntegers;
};
// test your code
const squaredIntegers = squareList(realNumberArray);
console.log(squaredIntegers);

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36.

Link to the challenge:
https://learn.freecodecamp.org/javascript-algorithms-and-data-structures/es6/write-higher-order-arrow-functions

Could you not put block of text inside backticks? it is incredibly tiring to read and I can’t read it all, too long… If you change that I will give it a try.

The above “expands” along these lines:

const squareList = function(arr){
  const squaredNumbers = arr.filter(function(num){
    return (num > 0 && num % parseInt(num) === 0);
  }
}

In pseudocode, that might look like:

  • create a function squareList, taking the parameter arr.
  • Within that function, create a const squaredNumbers.
  • set squaredNumbers to a filtered subset of arr.
  • The filtering algorithm is “if num is greater than zero AND num is an integer, preserve it; otherwise,drop it”.

You’re right about it being a great idea to have a solid understanding of higher-order functions. In essence, they are functions that operate on other functions – whether by receiving them as a parameter or by passing them back as a return value.

In the above chunk of code, we could rewrite it like so:

const isPositiveInt = (num) => num > 0 && Number.isInteger(num);
/**
 * The above could also be written:
 * const isPositiveInt = function(num){ 
 *   if (num > 0 && Number.isInteger(num) ){
 *     return true;
 *   } else {
 *     return false;
 *   }
 * } 
 *
 **/

const squareIt = (num) => Math.pow(num, 2);
// a function that returns num raised to the power of 2. Same as
//  num*num, but more self-documenting again. 

const filteredNumbers = arr.filter(isPositiveInt);    
const squaredNumbers = filteredNumbers.map(squareIt);

So we create a function, isPositiveInt(), which will return true if the number is a positive integer, and false otherwise. .filter(), which is a higher-order function, takes the isPositiveInt() as a parameter and runs it on each member of arr. Depending on whether they pass or not, filteredNumbers now contains just our positive integers.

We also created a second function, squareIt(), which simply squares a number. This we pass to another higher-order function, .map(), which applies that function to each member of filteredNumbers before assigning the entire array to squaredNumbers.

It is a little more time consuming to write the named functions like that second version, but then you can craft elegant, understandable code like this:

const squaredNumbers = arr.filter(isPositiveInt).map(squareIt);

Which shows you, right off, exactly what is happening. No muddle trying to understand the functions. Because, being a mature developer, you TESTED your isPositiveInt() in isolation before using in production code, right? lol). By doing that, you can test the functions independently. Test the squareIt() and isPositiveInt() as independent parts, then apply them with .map() and .filter().

Doing development with higher order functions takes a little thought, but also provides MASSIVE leverage.

Great article on the subject, chapter 5 in Eloquent Javascript.

Just a note: In my second code, I did away with the evalutaion expression using the modulo operator (%). There’s a reason for that. While it does do what you want it to do, using Number.isInteger() is reliable AND self-documenting. Don’t reinvent the wheel if you can avoid it. :wink:

1 Like

Thank you very much for that explanation. It definitely makes more sense that way, and I am going to start practicing creating named functions first. I like the way that looks, and, as you stated, how it tells you right off what is going on. I appreciate the time you took to explain this! (And Eloquent JavaScript is definitely on my current reading list, so thanks for the reminder!)

Glad I could help. It often just takes a slightly different perspective on the same question. New set of eyes and all that. :wink:

Definitely agree to that. Hopefully in writing out my thought process and understanding of it more, I’ll get to better explanations like that haha. :smiley: