Functional Programming is a Programming paradigm that treats computer operations as calculations of functions. The most important foundation of functional programming languages is the lambda Calculus, and the functions of the lambda calculus accept functions as inputs (parameters) and outputs (return values).
Write at the front:I did not know too much about functional programming before, and rarely divergent thinking and summary. It was not until recently that I began to write technical articles on the topic of functional programming that I realized after reading a lot of articles written by great minds that functional programming was used in many modules in actual projects. The process of writing this blog post is also the process of learning this programming paradigm systematically. I try my best to explain all the knowledge points involved in functional programming with what I have learned.
1. Pure functions
To understand how functional programming is implemented and actually used, you need to understand the concept of pure functions. When we talk about functions in functional programming, we mean functions in mathematics, such as functions f(x), g(x), and composite functions f(gx) that we learned in high school. Such a mathematical function can be regarded as a pure function.
Properties of pure functions:
- For the same input, you always get the same output
- There were no observable side effects
- Does not depend on the state of the external environment.
Some methods (functions) on arrays in JS have pure and impure differences:
Pure functions:
var arr = [1.2.3.4];
console.log(arr.slice(0.2)); / / [1, 2]
console.log(arr); // [1, 2, 3, 4]
Copy the code
slice
It’s a pure function, it doesn’t change the arrayarr
.
Impure functions:
var arr = [1.2.3.4];
console.log(arr.splice(0.2)); / / [1, 2]
console.log(arr); / / [3, 4]
Copy the code
splice
I changed the arrayarr
Phi is an impure function.
Compare these two examples:
- What we want to do is we want to call a function and get an intercept of the original array
arr
But do not want to change the original array arr. - The pure functions
splice
Feel free to put external variables or states (original arrayarr
), will lead to many unintended results, such side effects are not what we expect. - In the functional programming paradigm, of course, we want to use pure functions
slice
, it does not modify the original array, no side effects.
Consider an example of a function that depends on the state of the external environment:
Case 1:
var price = 69.99;
function discount(){
return price * 8.;
}
console.log(discount()); / / 55.992
console.log(price); / / 69.99
Copy the code
The discount method in Example 1 refers to the external state price, which can easily affect the value returned by the Discount method if you change the external state price, increasing system complexity and maintenance difficulties for large applications.
The solution to this problem is to pass the price as an argument to the function:
Example 2:
var price = 69.99;
function discount(p){
return p * 8.;
}
console.log(discount(price)); / / 55.992
console.log(price); / / 69.99
Copy the code
Although the results are the same, the difference is whether the price is passed in as a parameter and whether the parameters are received inside the function. Parameters are passed by value, a copy occurs, and the result returned does not affect the state outside the function. Example 1 is an impure function and example 2 is a pure function.
The purpose of using pure functions is:
In my opinion, pure function can be understood as the unit of minimum function, comparable to the basic unit of lego. Some of the complex requirements we implement are made up of these pure functions. Function combinations are explained in detail later.
2, Function Currying
Curryization was mentioned earlier in The Closure. Suppose there are two functions, A and b. When A is cached in A variable as the return value of B, and A refers to A variable in the scope of B, the representation is A closure. This feature can be used as an expression of functional programming.
Example: Here is an example of calculating a discount price:
// Cache the price after 20% discount
var discount80 = discount(8.);
// Cache the price after the 10% discount
var discount90 = discount(9.);
// The price of going Currying
function discount(percent){
return function(price){
returnprice * percent; }}console.log(discount80(69.99)); / / 55.992
console.log(discount90(69.99)); / / 62.991
Copy the code
The significance of curlization for functional programming is that it can cache the result of calling a function with one part of the parameters passed in, and then another part of the parameters passed in. The first call to the cache can be interpreted as preloading some final result. The second call to the cached function reference gives the final result.
Function combination
Another manifestation of functional programming is when an argument to a function is also a function. Anyone who has written code for many years has heard that functions are first class citizens. This means that a function can be assigned to a variable (function expression) or passed as an argument to another function. And it’s returned as a result in another function, which is called currying.
When a function is passed as a parameter to another function, as in the high school math form f(g(x)) mentioned at the beginning of this article.
In JS code:
function fn(func){
return func() + 20;
}
console.log(fn(function(){ / / 30
return 10;
}));
Copy the code
This example is nothing more than calling the passed parameter function inside of a function. We want to introduce combinations of functions.
Here is a simple implementation of combining functions. Functions that take only two arguments are combined sequentially from right to left.
function compose(f, g) {
return function(x) {
return f(g(x));
};
};
Copy the code
function add10(num){
return num + 10;
}
function add20(num){
return num + 20;
}
var res = compose(add10, add20);
console.log(res(5)); / / 35
Copy the code
Combine the pure functions add10 and add20 and cache the return function.
A practical example
So after introducing pure functions, function currying and function combinations, what can you do if you combine these?
Now, there was a demand that there was a discount currying method, there was a reserved price currying method, and then you combined the two methods to figure out a function that preserves two decimal places for a 10% discount. Let’s just plug in any price and figure out what we’re going to get.
// Cache the price after the 10% discount
var discount90 = discount(9.);
// Cache the price after 2 decimal places
var toFixed2 = toFixed(2);
// The price of going Currying
function discount(percent){
return function(price){
returnprice * percent; }}// Keep decimal Currying
function toFixed(num){
return function(price){
returnprice.toFixed(num); }}// Function combination
function compose(f, g) {
return function(x) {
return f(g(x));
};
};
// Cache a combination function that is 10% off and keeps 2 decimal places
var final_price = compose(toFixed2,discount90);
// Call to get the final result
console.log(final_price(69.99)); / / 62.99
Copy the code
- Preferential price function
discount
And keep the decimal placetoFixed
Two methods are usedThe function is curialized - Cache two currie methods that return results
discount90
和toFixed2
Are the twoPure functions compose
A combination ofdiscount90
和toFixed2
function
Five, some general function libraries
Underscore, Ramda, Lodash, and other JS libraries support the functional programming paradigm, and the apis they provide are essentially the same, so you can bring these third-party libraries into your projects and use the functional programming paradigm appropriately when writing business code for certain scenarios.
JS provides reverse and sort methods for arrays, but these methods change the array. They are not pure functions, so if you want to call them in sequence, you need to implement a method that copies the array.
// Define an array
var arr = [1.3.2];
// Define the ascending sort function
var diffAsc = function(a, b) { return a - b; };
// Cache sorting in ascending order
var sortAsc = sort(diffAsc);
// Function combination
function compose(f,g,h) {
return function() {
return function(x) {
return f(g(h(x)));
};
};
};
// Define the copy array method
function copy(arr){
return [].concat(arr);
}
// Define the array sort curlization method
function sort(type){
return function(arr){
returnarr.sort(type); }}// Define the array flip method
function reverse(arr){
return arr.reverse();
}
// Cache the combination function ();
var res = compose(reverse,sortAsc,copy)();
console.log(res(arr)); / / [3, 2, 1)
console.log(arr); // [1, 3, 2] does not change the original array
Copy the code
compose
Method is a simple implementation, it is not expansive, only fixed three levels of nested functions.
Well, let’s look directly at how ramda.js is implemented:
// Introduce the Ramda dependency
var R = require('ramda');
// Define an array
var arr = [1.3.2];
// Define the ascending sort function
var diffAsc = function(a, b) { return a - b; };
// The cache combines the r.loop and R.loop functions
var res = R.compose(R.reverse,R.sort(diffAsc));
console.log(res(arr)); / / [3, 2, 1)
console.log(arr); // [1, 3, 2] does not change the original array
Copy the code
Note:
R.compose
Function combinations are executed from right to left.R.reverse
和R.sort
These are pure functions that copy the old array and return a new array.- Many of the methods in Ramdajs are similar
R.sort
Like this. They are in themselves pro-Curryization, i.eR.sort( diffAsc, arr )
和R.sort(diffAsc)(arr)
Is equivalent, so the combinatorial function is usedR.compose
, the parameters inside can be passed like thisR.sort(diffAsc)
Final conclusion:
Functional programming has been around for quite a while, and I’ve been using this paradigm unknowingly when writing business code to implement some of the more complex features, but I haven’t been completely following the specification (there are still a lot of shortcomings along the way), and I’ve been able to summarize my shortcomings in this article.
For front-end development, we are fortunate that JS strongly supports the functional programming paradigm. Mastering this skill and using it in the right situations is something we should strive for.