Functional programming: Used to describe the mapping between data
Way of thinking: the relationship between the things that realize the world is abstracted to the functional world, demonstrating the relationship between the things through encapsulation, polymorphism and inheritance
It’s too hard to understand, but here are a few examples to look at the features and advantages of functional programming
The first common ones are functions as parameters, functions as return values, and functions can be stored in variables (i.e. first-class citizens of functions in the JS world).
1. Functions as arguments
// forEach function forEach (array, fn) { for(let i=0; i<array.length; i++){ fn(array[i]) } }Copy the code
2. Function as return value
Function once (fn) {let done = false return function () {if (! done) { done = true return fn.apply(this, arguments) } }Copy the code
The use of the above method abstracts the function we need rather than writing the implementation of the function every time we encounter a problem. This also abstracts the details and only requires us to focus on the goal. This way of calling a function in a function is also called a higher-order function.
Here’s another concept: closures
Nature: function at the time of execution can be carried in a stack (about function to perform, I wrote in detail in another article) when the function is performed after will remove from the execution stack, but the scope of the pile of members for the external references cannot be released, so the members of the inner function can access external function.
Let’s look at a closure use case
Function makePower (power) {return function (x) {return math.pow (x, power) } } let power2 = makePower(2) let power3 = makePower(3) console.log(power2(4))Copy the code
The above example is a good wrapper around using closures.
The third introduction will cover pure functions
Pure functions: The same input always produces the same output without any observable side effects
A pure function can be understood as a function in mathematics y=f(x).
Examples: Array slice (pure function) and splice (not pure function)
Slice returns the specified portion of the array without altering the original array
Splice operates on an array and returns that array, changing the original array
Benefits of using pure functions:
1. Can cache:
The following is an implementation of pure function caching
function memoize (f) {
let cache = {}
return function () {
let arg_str = JSON.stringify(arguments)
cache[arg_str] = cache[arg_str] || f.apply(f, arguments)
return cache[arg_str]
}
}
Copy the code
Testable: Pure functions make testing easier
Parallel processing: The manipulation of co-existing memory data in a multithreaded environment
The fourth function is currization
Use Cremation to solve hard coding problems
Eg: Function checkAge (age) {let min = 18 return age >= min} function checkAge (min, age) { return age >= min } checkAge(18, 24) checkAge(18, 20) checkAge(20, Function checkAge (min) {return function (age) {return age >= min} chechAge=min=>(age=>age=>min) let checkAge18 = checkAge(18) let checkAge20 = checkAge(20) checkAge18(24) checkAge18(20)Copy the code
Corrification: when a function has more than one argument, call it with the first argument and return a new function that takes the remaining arguments and returns the result.
The Case of Corrification in Lodash
const _ = require('lodash')
const match = _.curry(function (reg, str) {
return str.match(reg)
})
const haveSpace = match(/\s+/g)
const haveNumber = match(/\d+/g)
console.log(haveSpace('hello world'))
console.log(haveNumber('25$'))
const filter = _.curry(function (func, array) {
return array.filter(func)
})
console.log(filter(haveSpace, ['John Connor', 'John_Donne']))
const findSpace = filter(haveSpace)
console.log(findSpace(['John Connor', 'John_Donne']))
Copy the code
Analog implementation
function curry (func) { return function curriedFn (... If (args. Length < func.length) {return function () {return curriedFn(... Args. concat(array. from(arguments)))}} // Return func(... args) } }Copy the code
Conclusion:
1. Corrification allows us to pass a function with fewer arguments and get a new function that remembers some of the fixed arguments
2. This is a ‘cache’ of function parameters
3. Make functions more flexible and smaller in granularity
4. Multiple functions can be converted into unary functions, and functions can be combined to produce more powerful functions.
The fourth composition of intermediate functions
If we encounter multiple nested functions when one of the functions fails in execution, it is difficult to find the problem, so we need to separate and combine the functions inside. So you have the idea of combinations of functions.
Function combination: 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.
Let’s take loDash’s flowRIght method as an example (the input function is executed from right to left)
Simulation implementation:
// multifunction compose function compose (... fns) { return function (value) { return fns.reverse().reduce(function (acc, fn) { return fn(acc) }, value) } } // ES6 const compose = (... fns) => value => fns.reverse().reduce((acc, fn) => fn(acc), value) const toUpper = s => s.toUpperCase() const reverse = arr => arr.reverse() const first = arr => arr[0] const f = compose(toUpper, first, reverse)console.log(f(['one', 'two', 'three']))Copy the code
The fifth functor
1.Functor
Well, in functional programming we need to keep the side effects under control, exception handling, asynchronous operations and so on and so forth and so forth and so on and so forth and so forth and so forth and so forth and so forth
Functor
Container: Contains values and deformation relationships of values (functions)
Functor: is a special container implemented by an ordinary object that has a map method that runs a function to process values
Class Container {// of static method, Static of (value) {return new Container(value)} constructor (value) {this._value = value} // map Method, afferent deformation relation, Map each value in the Container to another Container map(fn) {return container.of (fn(this._value))}} // Test container.of (3).map(x => x + 2).map(x => x * x)Copy the code
Features of functors:
1. Functional programming operations do not operate directly on values, but are performed by functors
2. A functor is an object that implements the Map contract
3. We can think of a functor as a box that encapsulates a value
4. To process the values in the box, we need to pass a value-handling function (pure function) to the map method of the box, which will process the values
5. The final map method returns a box containing the new value (functor)