Table of contents
TogglePreface
This article will introduce a very important JavaScript function concept - higher-order function.
Higher-order functions are functions that return one or more functions as parameters, or one function as a result.
In this article, we'll take a closer look at what higher-order functions are, the benefits of using them, and how to use them in real-world applications.
- What is the function orientation?
- Pure function
- Higher-order function
- Currying
What is the function orientation?
The so-called function orientation, in a nutshell, is that the function itself is a variable. For example, a function can be declared using const, let, or var, and can be turned into an argument and passed into other functions, or added to arrays or objects.
Passing a function to another function as a quote.
const print = (message) => { console.log(`print function with ${message}`) } const helloMessage = () => { return "Hello Message" } print(helloMessage()); // print function with Hello Message
Add Array
const array = ["item0", (message) => console.log("I'm item function in array " + message)] console.log(array[0]); // item0 array[1]("argument "); // I'm item function in array argument
Add Objects
const object = { helloWorld: "Hello World", print: (message) => { console.log(`print function with ${message}`) } } object.print(object.helloWorld); // print function with Hello World
Pure function
When a function is only affected by an argument, it is called a pure function. Such a pure function, because it will not be interfered by other variables, such a function is sealed and will not be interfered by other variables and quotations, that is, it will have a side effect.
The so-called Side Effect refers to the external changes that occur during the execution of a function.
- Using Date.now() or Math.random()
- Use console.log()
- Modification of External Information
- Manipulating the DOM
- Raise an HTTP Request
Let's look at the following example, which is a non-pure function and is affected when external data is modified.
let y = 1; function xAdd(x) { return x + y; }; xAdd(5); //6
You can see that even if xAdd(5) is executed, the result will be different because of the change in y.
Therefore, we should turn the function into a pure function that is encapsulated and free from external influences. The advantage of a pure function is not only its independence, but also the fact that it is easier to write tests.
function sum(x, y) { return x + y; }; sum(1,2); //3
Higher-order function
A higher-order function is a function that "accepts or returns a function".
Acceptance means to enter a function as an Argument.
A call back function returns a function as a variable, and there are several different types of higher-order functions, such as map and reduce.
The above function guide is an example of one of these, so let's review it.
// Callback function, passed as a parameter in the higher order function function callbackFunction(){ console.log('I am a callback function'); } // higher order function function higherOrderFunction(func){ console.log('I am higher order function') func() } higherOrderFunction(callbackFunction);
In the above code, higherOrderFunction() is a HOF because we pass it a callback function as an argument.
The above example is simple enough, so let's take it a step further and see how we can use HOFs to write cleaner, more modular code.
How Higher Order Functions Work
Suppose you want to write a function that calculates the area and diameter of a circle. Being new to programming, the first solution that comes to mind is to write functions that calculate the area or the diameter of the circle separately.
const radius = [1, 2, 3]; // function to calculate area of the circle const calculateArea = function (radius) { const output = []; for(let i = 0; i< radius.length; i++){ output.push(Math.PI * radius[i] * radius[i]); } return output; } // function to calculate diameter of the circle const calculateDiameter = function (radius) { const output = []; for(let i = 0; i< radius.length; i++){ output.push(2 * radius[i]); } return output; } console.log(calculateArea(radius)); console.log(calculateDiameter(radius))
But did you notice the problem with the above code?
We're rewriting almost the same function over and over again, but the logic is slightly different, and the function we're writing can't be used over and over again, so let's see how we can use higher-order functions to write the same code:
const radius = [1, 2, 3]; // logic to clculate area const area = function(radius){ return Math.PI * radius * radius; } // logic to calculate diameter const diameter = function(radius){ return 2 * radius; } // a reusable function to calculate area, diameter, etc const calculate = function(radius, logic){ const output = []; for(let i = 0; i < radius.length; i++){ output .push(logic(radius[i])) } return output; } console.log(calculate(radius, area)); console.log(calculate(radius, diameter));
As you can see in the code above, we have only written one function, calculate(), to calculate the area and diameter of a circle. All we need to do is write the logic and pass it to calculate() and the function will do its job.
The code we write using high-level functions is concise and modular, each function does its own job, and we don't have to repeat anything here.
Suppose in the future we want to write a programme that calculates the circumference of a circle. All we need to do is write the logic to calculate the circumference and pass it to the calculate() function.
const circumeference = function(radius){ return 2 * Math.PI * radius; } console.log(calculate(radius, circumeference));
Other counterexamples and applications of arrow functions are also provided here.
const print = (message) => { console.log(`print function with ${message}`) } const helloMessage = () => { return "Hello Message" } print(helloMessage()); // print function with Hello Message
However, higher-order functions allow us to handle more convenient and complex situations.
const printNameByCondition = (condition, trueFunc, falseFunc) => { condition ? trueFunc() : falseFunc(); } const printHogan = () => console.log("Hello Hogan"); const printBobo = () => console. log("Hello BoBo"); printNameByCondition(true, printHogan, printBobo); // Hello Hogan printNameByCondition(false, printHogan, printBobo); // Hello BoBo
As you can see here, I have created a function with three Arguments, the last two of which are functions.
Through the first quote, to make a judgement, if it is true, the first function is executed, otherwise, the second function is executed.
How to Use Higher Order Functions
We can use higher-order functions in a variety of ways. When working with arrays, we can use the map(), reduce(), filter(), and sort() functions to manipulate and transform the data in the array.
HOF Handling Objects
You can create a new object from an object using the Object.entries() function.
HOF Using Functions
You can use the compose() function to create complex functions from simpler ones.
How to use some important higher order functions
JavaScript has many built-in higher-order functions, the most common of which are map(), filter(), and reduce(). Let's take a closer look at them.
How to use map() in JavaScript
The map() function takes an array and converts each value in the array without changing the original array. It is often used to convert an array of values into a new array with a different structure.
Example 1: Suppose we want to add to each element in the array 10. We can use the map() method reflects each element of the array by adding it to the 10.
const arr = [1, 2, 3, 4, 5]; const output = arr.map((num) => num += 10) console.log(arr); // [1, 2, 3, 4, 5] console.log(output); // [11, 12, 13, 14, 15]
In the above example, arr is an array of five elements:
We use the map method to apply a function to each element of the array, and then send back a new array containing the modified elements.
The call back function passed to the map uses an arrow function that takes a parameter num.
The function adds 10 to num (each element of the array) and returns the result.
Example 2: Here is an array of users. Suppose we only need the names of the users.We simply use the map() method to pull from the users array.
const users = [ {firstName: 'John', lastName: 'Doe', age: 25}, {firstName: 'Jane', lastName: 'Doe', age: 30}, {firstName: 'Jack', lastName: ' Doe', age: 35}, {firstName: 'Jill', lastName: 'Doe', age: 40}, {firstName: 'Joe', lastName: 'Doe', age: 45}, ] const result = users. map((user) => user.firstName + ' ' + user.lastName) console.log(result); // ['John Doe', 'Jane Doe', 'Jack Doe', 'Jill Doe', 'Joe Doe']
In the code above, users is an array of objects representing users. Each object has three attributes: last name, first name, and age.
We use the map() method to map each user to get the attributes firstName and lastName.
The call back function receives a parameter user, which represents an element in the users array (an object).
This function concatenates the user's name and lastName attributes and returns the results.
How to use filter() in JavaScript
The filter() function takes an array and sends back a new array containing only the values that match certain criteria.
它也不會改變原始陣列,通常用於根據特定條件從陣列中選擇資料集。
Example 1: Use the filter() function to return a legend from an array of numbers.
const arr = [1, 2, 3, 4, 5]; const output = arr.filter((num) => num % 2) // filter out odd numbers console.log(arr); // [1, 2 , 3, 4, 5] console.log(output); // [1, 3, 5]
In the above code, arr is an array of five elements:
filter is a method for creating a new array whose elements must pass the tests specified in the provided callback function.
The callback function checks if num is odd by checking if num is divisible by 2 (num % 2). If num is not divisible by 2, the function returns true, otherwise it returns false.
When using filter on arr, the function is applied to each element of the array, creating a new array that contains only the elements that return true or pass the specified condition. The original array remains unchanged and returns the results.
Example 2: You can use filter() to return only those users who are older than 30 years old in the array.
const users = [ {firstName: 'John', lastName: 'Doe', age: 25}, {firstName: 'Jane', lastName: 'Doe', age: 30}, {firstName: 'Jack', lastName: ' Doe', age: 35}, {firstName: 'Jill', lastName: 'Doe', age: 40}, {firstName: 'Joe', lastName: 'Doe', age: 45}, ] // Find the users with age greater than 30 const output = users.filter(({age}) => age > 30) console.log(output); // [{firstName: 'Jack', lastName: 'Doe', age: 35} , {firstName: 'Jill', lastName: 'Doe', age: 40}, {firstName: 'Joe', lastName: 'Doe', age: 45}]
In the above code, users is an array of users. Each object has three attributes: first name, last name, and age.
Uses a filter on the users array and a callback function for each element in the array.
A function takes a parameter, in other words, an object that has been reassembled into a single attribute age.
This function checks if the age is greater than 30. If it is, the function returns true, otherwise. return false。
When you use the filter on users, it uses this function on each element of the array, creating a new array that contains only the elements that you passed the function to.. return true, and. returnresult. The original users array remains unchanged.
How to use reduce() in JavaScript
reduce() is a relatively complex function in many people's minds, so if you've encountered the reduce() method before and can't figure it out at first, read on!
One question we may have is: why use reduce()? Since there are already many good functions, how do we decide which one to use, and when to use it?
In the case of reduce(), it should be used when you want to perform an operation on an array element and return a single value.
Single value: the cumulative result of applying the function repeatedly to the array elements.
For example, you can use reduce() to sum all the elements of an array, find the maximum or minimum value, combine multiple objects into a single object, or split different elements of an array. Let's walk through some examples.
Example 1: Use reduce() to find the sum of all the elements in an array:
const numbers = [1, 2, 3, 4, 5]; const sum = numbers.reduce((total, currentValue) => { return total + currentValue; }, 0) console.log(sum); // 15
In this example, the reduce() method is used in an array and passes a callback function with two parameters: total and currentValue.
The total parameter is the sum of the values returned when the function is used, and currentValue is the current element of the array being processed.
The second parameter of reduce() is also the initial value, which is 0 in the above example, and is used as the initial value of total for the first stack.
In each superposition, the function adds the current value to the total and. returnthe new value of the total number.
Next, the reduce() method uses the returned values as the total for the next iteration until all the elements in the array have been processed.
Finally, it returns the final value of the total, which is the sum of all the elements in the array.
例 2:使用 reduce() 求數列中的最大值:
let numbers = [5, 20, 100, 60, 1]; const maxValue = numbers.reduce((max, curr) => { if(curr > max) max = curr; return max; }); console.log( maxValue); // 100
In this example, we again use the max and curr parameters in the callback function, this time without passing the second parameter in the reduce() method. Therefore, the default value will be the first element in the array.
The callback function first checks to see if the current element, curr, is greater than the current maximum value, max; if it is, it updates the value of max to make it the current element; if it is not, it does not update max. If not, it doesn't update max, and finally, it returns the value of max.
In this example, the reduce() method first sets max to 5 and curr to 20, then it checks to see if 20 is greater than 5, and if it is, it updates max to 20.
Then set curr to 100 and check if 100 is greater than 20, which it is, so update max to 100.
This process continues until all the elements of the array have been processed. max will end up being the maximum value in the array, which in this case is 100.
Advantages of Higher Order Functions
Using higher order functions has some important benefits for developers.
Firstly, higher-order functions make the code more concise and easier to understand, which helps to improve the readability of the code, helps to speed up the development process, and makes the code easier to use.
Secondly, higher-order functions help to group code together, making it easier to maintain and extend.
Currying
Currying is a special and important technique in higher-order functions.
It is possible to pass in different levels of quotes from a higher-order function, or to add a prefix to a higher-order function by using this concept.
const userLogs = userName => message => console.log(`${userName} -> ${message}`) const log1 = userLogs("Hogan"); log1("Hello World"); log1("Hello") ; const log2 = userLogs("Bobo"); log2("Hello World"); log2("Hello");
This is also implemented using an example, which also gives two different prefixes for the higher-order functions
Conclusion
This article explores the concept of function orientation, what are higher-order functions, the benefits of using higher-order functions, and how to use higher-order functions in real-world applications, as well as a relatively small introduction to what Curring does, and an introduction to Pure Functions.
By using higher-order functions, developers can write smarter, modularise code and make it clearer and easier to use.
Feel free to leave a comment if you have any suggestions or questions!
If you like this series of articles, please do not hesitate to click like and share it so that more people can see it!
Quote
React Vernacular Campaign 05-Higher-order function
Other article references
JavaScript Async Await - React Vernacular Campaign 03
JavaScript ES6 Object - React Vernacular Campaign 02