Higher order functions in javascript: what is it?

Original author: Sukhjinder Arora
  • Transfer
We present you a translation of the article Sukhjinder Arora , published on the resource Bits and Pieces . Learn under the cat about the higher order functions in JavaScript and some other functions built into this language.


Photo NESA by Makers from Unsplash website

When learning to program in JavaScript, you must have come across the concept of higher order functions . Although this concept may seem frightening, in fact, everything is not so difficult.

Thanks to the ability to work with higher-order functions, JavaScript is suitable for functional programming.

Higher-order functions are common in JavaScript. If you worked with it for some time, it is very likely that you used such functions without even realizing it.

To get a complete picture of higher-order functions, you first need to understand what functional programming and first-class functions are .

Board: Repeated use of JavaScript functions often leads to duplicates. To avoid this, use Bit (GitHub) . You can easily find new functions, share them and re-apply them with minimal changes in management. Try, do not hesitate.

What is functional programming?


Without going into details, functional programming is programming, in which some functions are passed as arguments to other functions and return third functions as values. In functional programming, we think and operate with functions.

Functional programming is done in languages ​​such as JavaScript, Haskell, Clojure, Scala, and Erlang.

What are first class features?


When learning to work with JavaScript, you most likely heard that for it, the functions are first-class citizens. The fact is that in JavaScript, as in any other functional programming language, functions are objects.

Specifically for JavaScript functions are objects of a special kind (objects Function, or functors). For example:

functiongreeting() {
  console.log('Hello World');
}
// Invoking the function
greeting();  // prints 'Hello World'

To show that functions in JavaScript are objects, we can do something like this:

// We can add properties to functions like we do with objects
greeting.lang = 'English';
// Prints 'English'console.log(greeting.lang);

Note: although the above described works fine in javascript, you should not abuse it. It is impossible to assign random properties to functors - it is better to use ordinary objects.

In JavaScript, everything you can do with other entities, such as an object, a string, or a number, also applies to functions. They can be passed, including as arguments to other functions (then they are called callback-functions or callback functions), assigned to variables, and so on. This is why JavaScript functions are called first class functions.

Assigning Functions to Variables


JavaScript allows you to assign functions to variables. For example:

const square = function(x) {
  return x * x;
}
// prints 25
square(5);

You can also transfer them. For example:

const foo = square;
// prints 36
foo(6);

Passing functions as arguments


We can pass functions as arguments to other functions. For example:

functionformalGreeting() {
  console.log("How are you?");
}
functioncasualGreeting() {
  console.log("What's up?");
}
functiongreet(type, greetFormal, greetCasual) {
  if(type === 'formal') {
    greetFormal();
  } elseif(type === 'casual') {
    greetCasual();
  }
}
// prints 'What's up?'
greet('casual', formalGreeting, casualGreeting);

So now, knowing what functions are first class, let's turn to higher order functions in JavaScript.

Higher order functions


Higher-order functions are functions that work with other functions, taking a function as an argument or returning a function as a result.

Examples of higher-order functions, which are already built into the language, are Array.prototype.map, Array.prototype.filter, and Array.prototype.reduce.

Higher order functions in action


Let's look at a few examples of higher-order built-in functions and compare them with solutions that do not use higher-order functions.

Array.prototype.map
The method map()creates a new array with the result of calling the function to be passed for each element of the initial array. The method map()takes each value of the callback function and creates a new array using these values.

Callback-function passed to the method map()accepts three arguments: element, indexand array.

Consider this with a few examples.

Example №1
Suppose we have an array of numbers, and from it we want to create a new array in which each number from the initial array would be doubled. How can we solve this problem with and without a higher order function?

No higher order function:

const arr1 = [1, 2, 3];
const arr2 = [];
for(let i = 0; i < arr1.length; i++) {
  arr2.push(arr1[i] * 2);
}
// prints [ 2, 4, 6 ]console.log(arr2);

Using a higher order function map:

const arr1 = [1, 2, 3];
const arr2 = arr1.map(function(item) {
  return item * 2;
});
console.log(arr2);

The code can be made even shorter by using the arrow function.

const arr1 = [1, 2, 3];
const arr2 = arr1.map(item => item * 2);
console.log(arr2);

Example # 2
Let's say we have an array containing years of birth of several people, and from it we want to create a new array in which their ages will be.

No higher order function:

const birthYear = [1975, 1997, 2002, 1995, 1985];
const ages = [];
for(let i = 0; i < birthYear.length; i++) {
  let age = 2018 - birthYear[i];
  ages.push(age);
}
// prints [ 43, 21, 16, 23, 33 ]console.log(ages);

Using a higher order function map:

const birthYear = [1975, 1997, 2002, 1995, 1985];
const ages = birthYear.map(year =>2018 - year);
// prints [ 43, 21, 16, 23, 33 ]console.log(ages);

Array.prototype.filter
The method filter()creates a new array with all the elements that pass the test specified in the function being passed. Callback-function passed to the method filter()accepts three arguments: element, indexand array.

Consider this with a few examples.

Example №1
Imagine that we have an array containing objects with the properties “name” and “age”. From it we want to create a new array in which only adults (eighteen and older) will be listed.

No higher order function:

const persons = [
  { name: 'Peter', age: 16 },
  { name: 'Mark', age: 18 },
  { name: 'John', age: 27 },
  { name: 'Jane', age: 14 },
  { name: 'Tony', age: 24},
];
const fullAge = [];
for(let i = 0; i < persons.length; i++) {
  if(persons[i].age >= 18) {
    fullAge.push(persons[i]);
  }
}
console.log(fullAge);

Using a higher order function filter:

const persons = [
  { name: 'Peter', age: 16 },
  { name: 'Mark', age: 18 },
  { name: 'John', age: 27 },
  { name: 'Jane', age: 14 },
  { name: 'Tony', age: 24},
];
const fullAge = persons.filter(person => person.age >= 18);
console.log(fullAge);

Array.prototype.reduce
The method reduceapplies a function to each value of the array, reducing it to a single value. The reduce method takes two arguments:
  1. callback function to be processed;
  2. optional parameter initialValue(first argument when first calling the function).

Callback-function takes four arguments: accumulator, currentValue, currentIndex, sourceArray.

If the parameter initialValuewas passed, the argument accumulatorwill be equal to the argument initialValue, and the argument will be equal to the currentValuefirst element of the array.

If the parameter initialValuewas not passed, the argument accumulatorwill be equal to the first element of the array, and the currentValuesecond element of the array will be taken as the argument .

Example # 1
Suppose we need to find the sum of the numbers in the array.

Using a higher order function reduce:

const arr = [5, 7, 1, 8, 4];
const sum = arr.reduce(function(accumulator, currentValue) {
  return accumulator + currentValue;
});
// prints 25console.log(sum);

Each time the callback function is applied to each value from the array, the argument accumulatorsaves the result of the previous action returned by the function, and currentValuetakes the next value of the array. Upon completion, the result is stored in a variable sum.

In addition, we can pass this function an initial value:

const arr = [5, 7, 1, 8, 4];
const sum = arr.reduce(function(accumulator, currentValue) {
  return accumulator + currentValue;
}, 10);
// prints 35console.log(sum);

No higher order function:

const arr = [5, 7, 1, 8, 4];
let sum = 0;
for(let i = 0; i < arr.length; i++) {
  sum = sum + arr[i];
}
// prints 25console.log(sum);

As you can see, with the help of the higher order function, the code can be made neater, shorter and more capacious.

Creating your own higher order function


Up to this point, we have considered various higher-order functions built into the language. It's time to create your own higher order function.

Imagine that JavaScript would not have its own method map. We could build it ourselves, thereby creating our own higher order function.

Let's say we have an array of strings, and from it we want to create an array of integrals, in which each element will represent the length of a string from the initial array.

const strArray = ['JavaScript', 'Python', 'PHP', 'Java', 'C'];
functionmapForEach(arr, fn) {
  const newArray = [];
  for(let i = 0; i < arr.length; i++) {
    newArray.push(
      fn(arr[i])
    );
  }
  return newArray;
}
const lenArray = mapForEach(strArray, function(item) {
  return item.length;
});
// prints [ 10, 6, 3, 4, 1 ]console.log(lenArray);

In the above example, we have created a higher-order function mapForEachthat takes an array and a callback function as arguments fn. This function is cyclically applied to each element of the array and calls a callback function fnas part of the function call newArray.pushin each iteration.

The callback function fntakes the current element of the initial array and returns the length of this element, which is stored inside the new array newArray. After the iteration is completed, the array is newArrayreturned as a result and is assigned by the array lenArray.

Conclusion


We learned what higher-order functions are and examined some of the functions built into the language. We also learned how to create your own higher-order functions.

In short, higher-order functions work like ordinary functions, but they have the additional ability to get other functions as an argument and return them as a result.

That's all. If this article seemed useful to you, you can also follow me on Medium and on Twitter . Feel free to comment - if you have questions! I will be happy to help. :)

Also popular now: