Functional programming concepts

The essence of a program is to derive output from input. X -> f(connection, mapping) -> y, y=f(x).

The function is a first-class citizen, which is just an ordinary object. It can be an argument to another function, a return value of a function, or stored as a variable

/ / the function
const num1 = 2;  
const num2 = 3;  
const sum = num1 + num2;  
// console.log(sum)

// Function (function expression that assigns a function as a variable)

const add = (num1, num2) = > { 
    return num1 + num2;  
}  
// console.log(add(num1, num2))

Copy the code

Higher-order functions

Higher-order functions can let us to common generic methods (forEach, map, reduce, some, every, find, findIndex)

To satisfy higher-order functions, one of the conditions must be met:

One function can take arguments from another function. 2. The return value of a function is another functionCopy the code
// forEach,filter

// write the forEach function
const forEach = (array, fun) = > {
    for (let index = 0; index < array.length; index++) {
        const element = array[index];
        fun(element)
    }
}
forEach([1.2.3.4.5].num= > console.log(num * 2))
// 2 4 6 8 10

// Write the filter function
const filter = (array, fun) = > {
    const result = [];
    for (let index = 0; index < array.length; index++) {
        const element = array[index];
        if (fun(element)) result.push(element)
    }
    return result; 
}
console.log(filter([1.2.3.4.5].num= > num % 2= = =0))
// [2, 4]

// Functions as return values, such as makeFn,once
const makeFn = () = > {
    const msg = 'hello function';
    return _= > console.log(msg);
}
makeFn()()
// hello function

// Only pay once
const once = fn= > {
    let done = false;
    return function() {
        if(! done) { done =true;
            fn.apply(this.arguments)}}}const pay = once((money) = > {
    console.log(Pay `${money}Yuan `)
})
pay(5)
pay(5)
pay(5) payment5yuanCopy the code

The closure function

To call the inner function of a function in another scope and access a member of that function’s scope.

The essence of closures: functions are placed on an execution stack at execution time and removed from the stack when the function completes execution, but scoped members on the heap cannot be freed because of external references, so internal functions can still access the members of the external function

The above makeFn and once both use closures, which must be a higher-order function because the function is returned

/* For example, if I want to raise a number to the NTH power, if I have a large number of values and need to raise it to the 2nd power, I can raise it to the 2nd power and pass the desired values. Here, the outer function argument power is not destroyed after the makePower completes, and the inner function continues to be used, thus forming a closure */
const makePower = (power) = > num= > Math.pow(num, power);

const power2 = makePower(2);
const power3 = makePower(3);

console.log(power2(3))
console.log(power3(3))
Copy the code

Pure functions

The same input will always produce the same output without any observable side effects (meaning external states),A pure function is like a function in mathematics, y = f(x).

// An impure function,mini is an external configuration property, if changed, does not satisfy the condition of a pure function
const mini = 18;
const checkAge = age= > age > mini;

// Change to a pure function
const checkAge = age= > {
    const mini = 18;
    return age > age;
}
Copy the code

Side effects

Side effects can make your functions impure. Side effects cannot be completely banned. Try to keep them under control, as in the example of pure functions above.

The sources of side effects are as follows: 1. Configuration file 2. Database 3

Currie,

When a function has multiple arguments, it can be called by passing some arguments and then returning a new function that accepts the rest of the arguments until the arguments are accepted and the result is returned

Equivalent to batching a multi-parameter function, we can get the function cache

Characteristics: 1. Currization allows us to pass fewer parameters to a function to get a new function that has remembered some fixed parameters. 2. This is a cache of function parameters. 3. Make functions more flexible and smaller in granularity. 4. You can convert multivariate functions into unary functions, and you can combine functions to produce powerful functions

// Currified checks the age function
const checkAge = mini= > age= > age > mini;
const check18 = checkAge2(18);
console.log(check18(20));
// true
Copy the code
/ * yourself realizing the curry, the first parameter is a function, the function of parameter N, and the return value is a letter, when this function is curry, call this function, if the parameter is less than N, continues to return a function, etc For the rest of the parameters passed, if the parameter is equal to N, directly back to the final result * /
const curry = fn= > {
    return function curriedFn(. args) {
        // Determine the number of arguments and parameters
        if(args.length < fn.length){
            return function() {
                returncurriedFn(... args, ... arguments); }}return fn(...args);
    }
}

const ownerCurriedFilter = curry((fn, array) = > array.filter(fn))

// Both methods give the same result
console.log(ownerCurriedFilter(num= > num % 2= = =0[1.2.3.4]))
console.log(ownerCurriedFilter(num= > num % 2= = =0) ([1.2.3.4]))
// [2, 4]
Copy the code

Function composition

If a function needs to be processed by multiple functions to get the final value, it is possible to combine the intermediate functions into a single function

Features: 1. Functions are like data pipes, and function combination is to connect these pipes and make data pass through multiple pipes to form the final result 2. Function combinations are executed from right to left by default. 3. Function combinations satisfy the associative law

const reverse = array= > array.reverse();
const first = array= > array[0];
const toUpper = str= > str.toUpperCase();

// The lodash library is used
const flowRightFn = _.flowRight(toUpper, first, reverse);
console.log(flowRightFn(['aaa'.'bbb'.'ccc']));
// CCC
Copy the code
/* To implement function combination, the first parameter is a set of functions, return a function, characteristic is the last function to execute the return value of the next function parameter, similar to the pipeline form, until all the functions return a result */
const compose = (. args) = > {
    return function(value) {
        return args.reverse().reduce((current, fn) = > {
            return fn(current)
        }, value)
    }
}
const flowRightFn = compose(toUpper, first, reverse);
console.log(flowRightFn1(['aaa'.'bbb'.'ccc']));
// CCC
Copy the code

Lodash is a very useful function library, the string, array, object processing functions are pure functions, fp module functions are currie, can be directly used. Proficiency with the Lodash library can increase development efficiency

The Pointfree pattern is a programming style that is a combination of functions

Features: 1. It is not necessary to specify the data to be processed. 2. You need to define some auxiliary basic operation functions

Funtor functor

The purpose is to control side effects in functional programming, exception handling, asynchronous operations, etc. A box is a box that contains a value that is not visible to the outside world. It takes a specific execution to get the value, or to manipulate the value, and then returns a box that contains your new value.

Features: 1. The operations of functional programming do not operate directly on values, but are performed by functors 2. Functors are implementations; 3. We can think of a functor as a box that encapsulates a value of 4. To process the value in the box, we need to pass a pure function to the map of the box to process the value. The final map method returns a functor containing the new value

// A basic functor, a container, wraps a value
class Container {
    // of static methods that create objects without the new keyword
    static of (value) {
        return new Container(value)
    }

    constructor(value) {
        this._value = value
    }
    // the map method, passing in functions that map each value in a container to another container
    map(fn) {
        return Container.of(fn(this._value));
    }
}

Container.of(2)
.map(x= > x + 2)
.map(x= > x * x)
Copy the code

IO functor

IO functors can store impure actions in _value, delaying the execution of the missing operation to ensure that the current operation is pure 3. Nonexistent operations are handed over to the caller

/* _fn.flowright is a combination of functions in Lodash, so we want to process the value returned by the _value function. We can write it anywhere in the call, because the combination of functions will process the _value function */ first
class IO {
    static of() {
        return new IO(function() {
            return x
        })
    }
    constructor(fn) {
        this._value = fn;
    }

    map(fn) {
        // Combine the current value and the incoming fn into a new function
        return new IO(_fn.flowRight(fn, this._value))
    }
}
Copy the code