Basic Knowledge of Functional Programming#
Why Learn Functional Programming?#
In the past, imperative programming dominated. Imperative programming is the smallest granularity of programming, allowing precise control over the state of each element.
However, small granularity means high freedom and also means complexity. Because of the high granularity, if you want to implement a simple and common function, you have to build it from scratch. Many infrastructures cannot be reused.
There are some functions that can be reused, such as common comparisons, sorting, filtering, and so on. These functions can be reused, but in imperative programming, these functions are "accessories" rather than "core".
Functional programming is a declarative programming paradigm, and its core is "functions". The core of functional programming is "functions", not "state".
OK, so what is the essence of functional programming? If we talk about the idea, it is "layering". It is the process of dividing a core function into multiple "accessory functions". If we talk about implementation, it is the "API syntax of accessory functions".
What is Currying?#
If there are two essential operations in functional programming, they are undoubtedly currying and function composition. Currying is like a processing station on a production line, and function composition is our production line, which consists of multiple processing stations.
f(a,b,c) → f(a)(b)(c)
Let's try to write a curry version of the add function
var add = function(x) {
return function(y) {
return x + y;
};
};
const increment = add(1);
increment(10); // 11
Why is this unit function important? Do you remember what we said before, that a function can have only one return value?
If we want to smoothly assemble the production line, I must ensure that the output of each processing station can flow to the input of the next workstation. Therefore, the processing stations on the production line must all be unit functions.
Now it is easy to understand why currying works so well with function composition, because the result of currying is exactly a single input.
Related Syntax of Functional Programming#
Functional programming in JavaScript supports multiple practical functions, mainly including but not limited to the following categories:
-
Mapping: Apply a function to each element in the array and create a new array that contains the results of applying the function.
const numbers = [1, 2, 3, 4]; const doubled = numbers.map(x => x * 2); // [2, 4, 6, 8]
-
Filtering: Determine whether to keep the elements in the array based on a test function and create a new array that contains the elements that pass the test.
const numbers = [1, 2, 3, 4]; const evens = numbers.filter(x => x % 2 === 0); // [2, 4]
-
Reducing: Combine the elements of the array into a single value through a reducer function.
TheArray.prototype.reduce()
method is a very powerful tool in JavaScript, used to merge (or "reduce") all elements in an array into a single value. This method is very useful for operations such as accumulating values in an array, merging array contents, or implementing complex data transformations in a single traversal.The basic usage of the
reduce
method is as follows:array.reduce(callback(accumulator, currentValue, currentIndex, array), initialValue)
The default parameters of the callback function are as follows:
accumulator: The accumulated value returned by the callback; it is the value accumulated from the previous call to the callback, or the initial value (initialValue) provided.
currentValue: The element currently being processed in the array.
currentIndex (optional): The index of the current element being processed in the array. If initialValue is provided, the starting index is 0; otherwise, it is 1.
array (optional): The array on which the reduce method is called.initialValue (optional): The value of the first parameter (accumulator) when the callback function is called for the first time. If no initial value is provided, the first element of the array will be used.
const numbers = [1, 2, 3, 4]; const sum = numbers.reduce((accumulator, current) => accumulator + current, 0); // 10
-
Every: Check if all elements in the array satisfy the provided testing function.
The return value ofevery
is always a boolean. If it accepts a non-boolean value, it will convert it to a boolean for calculation.
In JavaScript, theArray.prototype.every()
method does expect a function as a parameter, which tests each element in the array. If the callback function returns a truthy value for each element, theevery
method will returntrue
; otherwise, it will returnfalse
.
This callback function does not necessarily have to return a boolean (true
orfalse
). Any value in JavaScript can be considered as a truthy value or a falsy value. If the value returned by the callback function can be converted totrue
in a boolean context, then it is considered a truthy value. Common falsy values include0
,null
,undefined
,NaN
, an empty string""
, andfalse
itself. All other values are considered truthy.
For example, if the callback function returns the number1
, although1
is not a boolean value, it is a truthy value, soevery
will interpret it astrue
. If the callback function returns0
(a falsy value),every
will interpret it asfalse
.const numbers = [1, 2, 3, 4]; const allPositive = numbers.every(x => x > 0); // true
-
Some: Check if at least one element in the array satisfies the provided testing function. Same as
every
.const numbers = [1, 2, 3, 4]; const hasNegative = numbers.some(x => x < 0); // false
-
Find: Return the value of the first element in the array that satisfies the provided testing function.
const numbers = [1, 2, 3, 4]; const firstEven = numbers.find(x => x % 2 === 0); // 2
-
FindIndex: Return the index of the first element in the array that satisfies the provided testing function.
const numbers = [1, 2, 3, 4]; const indexOFEven = numbers.findIndex(x => x % 2 === 0); // 1
-
Sorting: Sort the elements of the array and return the sorted array.
const numbers = [4, 2, 3, 1]; numbers.sort((a, b) => a - b); // [1, 2, 3, 4]
-
Slicing: Return a portion of the array without modifying the original array. Return a new array that includes the elements in the array from the start (inclusive) to the end (exclusive).
const numbers = [1, 2, 3, 4]; const middleTwo = numbers.slice(1, 3); // [2, 3]
These functions are the basic tools of functional programming in JavaScript. They provide a declarative and immutable programming paradigm, which helps write clearer and more maintainable code.
Now let's try to write down these functional JS APIs.
Simply write down the functional JS APIs you are familiar with
- every: Its purpose is to execute the callback for each element of the array, and if the return value of the callback for each element of the array is true, it will return true. If one of them is not true, it will return false.
- some: Same as every, if one returns true, it will return true; if all return false, it will return false.
- map: Its purpose is mapping, which means that each number in an array is transformed into the return value of the callback function, and then the results are combined to return an array.
- filter: Its purpose is filtering, which means that the numbers that satisfy the callback function are retained, and the numbers that do not satisfy the callback function, that is, the numbers for which the callback function returns false, are deleted. The callback function it accepts also needs to accept a boolean type.
- find: Its purpose is to query each number in the array. If the number in the array satisfies the callback function, it will return this number. The callback it accepts also needs to accept a boolean type.
- findindex: Same as find, but it returns the index of the number.
- sort: Sorting, it sorts the numbers in the array according to the rules. How to sort according to the rules? It accepts two numbers. If it returns a negative number, it means that a comes first; if it returns a positive number, it means that b comes first; if it returns 0, it means no change. Finally, it returns the sorted array.
- slice: Slicing, it accepts two parameters and does not accept a callback. Its two parameters are the starting element and the ending element, and it returns an array of [,), which means an array that does not include the ending element.
- reduce: It is a function that normalizes the entire array. It can turn an array into a number. Simple applications include accumulators. It can also do operations such as turning an array into a list. It accepts two parameters, a callback function and an initial value. The first value of the callback function is the return value before, and the second value is the current value.
These are not just functional programming, but also some object methods of Array. What other object methods are there?#
concat()
: Concatenates two or more arrays and returns a new array.copyWithin()
: Copies a sequence of elements within the array to the position starting at the specified destination index and replaces the original elements.entries()
: Returns a new Array Iterator object that contains the key/value pairs for each index in the array.every()
: Tests whether all elements in the array pass the test implemented by the provided function.fill()
: Fills all the elements in an array from a start index to an end index with a static value.filter()
: Creates a new array with all elements that pass the test implemented by the provided function.find()
: Returns the value of the first element in the array that satisfies the provided testing function.findIndex()
: Returns the index of the first element in the array that satisfies the provided testing function.forEach()
: Executes a provided function once for each array element.from()
: Creates a new array instance from an array-like or iterable object.includes()
: Determines whether an array contains a specified element, returningtrue
orfalse
as appropriate.indexOf()
: Returns the first index at which a given element can be found in the array, or -1 if it is not present.isArray()
: Determines whether the passed value is an array.join()
: Joins all elements of an array into a string and returns the string.keys()
: Returns a new Array Iterator object that contains the keys of each index in the array.lastIndexOf()
: Returns the last index at which a given element can be found in the array, or -1 if it is not present.map()
: Creates a new array with the results of calling a provided function on every element in the array.pop()
: Removes the last element from an array and returns that element.push()
: Adds one or more elements to the end of an array and returns the new length of the array.reduce()
: Applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.reduceRight()
: Applies a function against an accumulator and each value of the array (from right to left) to reduce it to a single value.reverse()
: Reverses the order of the elements of an array in place. The first array element becomes the last, and the last array element becomes the first.shift()
: Removes the first element from an array and returns that removed element.slice()
: Returns a shallow copy of a portion of an array into a new array object selected from start to end (end not included).some()
: Tests whether at least one element in the array passes the test implemented by the provided function.sort()
: Sorts the elements of an array in place and returns the sorted array.splice()
: Changes the contents of an array by removing or replacing existing elements and/or adding new elements.toString()
: Returns a string representing the specified array and its elements.unshift()
: Adds one or more elements to the beginning of an array and returns the new length of the array.valueOf()
: Returns the primitive value of the specified object.