What is functional programming?

Functional Programming (FP), FP is one of the Programming paradigms, common Programming paradigms are: object-oriented Programming, procedural Programming

  • Object oriented programming: it is to abstract things in the real world into a class with specific values and methods, through inheritance, encapsulation, polymorphism to achieve the connection of things and events
  • Functional programming way of thinking: putting things between a series of complexcontactEvents abstracted to a program (to abstract an operational procedure)
    • The essence of the program: based on the input to obtain the corresponding output through operations. You take x, you do a bunch of operations, you print y. The y = f (x);
    • The function in functional programming is not the function (method) in the program, but the function in mathematics, namely the mapping relation. Such as: y = sin (x),
    • Pure function: The same input always gets the same output

Why Study FP(Functional Programming)

  • React’s popularity has led to a growing interest in functional programming
  • Vue3 also began to make heavy use of functional programming
  • Functional programming can discard this. Even in the process of using, do not pay attention to this pointing problem
  • Better use of Tree Shaking to filter out useless code during project packaging (improvements to Vue3)
  • Convenient for testing and parallel processing
  • There are many libraries (Lodash, underscore, Ramda) that can help us with function development

Functions are first-class citizens (functions can be used as variables)

A programming language is said to have first-class functions when its functions can be treated as variables.

  • Functions can be stored in variables
  • Functions can be arguments
  • A function can be a return value

A Function in JS is an ordinary object. It can be stored in variables, used as a parameter or return value of a Function, or even constructed a new Function by using new Function() when the program is running.

Higher-order functions

What is a higher-order function
  • You can pass a function as an argument to another function

    function forEach(array,fn){
    	for(let i = 0; i < array.length; i++){
            fn(array[i])
        }
    }
    Copy the code
  • You can take a function as the return value of another function

    function makeFn(){
    	let msg = "hello world!"
        return function(){
            console.log(msg)
        }
    }
    
    const fn = makeFn();
    fn()
    Copy the code
The meaning of using higher-order functions
  • Abstract details, that is, you don’t need to focus on the internal implementation details, just the goal you want to achieve

  • Higher-order functions are used to abstract general problems, simplify code, and achieve code reuse

    // Process oriented approach
    let array = [1.2.3.4];
    for (let i = 0; i< array.length; i++){
        console.log(array[i])
    }
    
    // Higher order functions
    let array = [1.2.3.4];
    forEach(array,item= > {
        console.log(item); .// something you want
    })
    Copy the code
Commonly used higher-order functions
  • forEach
  • map
  • filter
  • every
  • some
  • find/findIndex
  • reduce
  • sort
  • .

Closure

Concept:

Functions are bundled together with applications of their surrounding state (lexical context) to form closures

Speaking human: Outside of a function, you call a function inside that function and have access to members of the function’s scope (simply, variables in that function’s scope). In this case, you can say that the function forms a closure.

The nature of closures

Functions are placed on an execution stack at execution time, and removed from the stack when the function is finished executing. Scoped members on the heap cannot be freed because they are referenced externally, so the inner function can still access the members of the outer function.

Closure example
// Generates a function that computes the power of a number
function makePower(power){
	return function(x){
		return Math.pow(x,power)
    }
}

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

console.log(power2(3)); / / 9
console.log(power3(3));	/ / 27
Copy the code

Pure Function

The concept of pure functions
  • The same input will always get the same output, without any observable side effects. You can think of it as a function of y=f(x).
  • Lodash is a library of pure functions that provides methods to operate on arrays, numbers, objects, strings, functions, and more
  • An array ofsliceandspliceThey are: pure function, impure function
    • sliceReturns the specified portion of the array, without changing the function
    • spliceOperating on an array and returning it changes the array
  • Functional programming does not preserve the middle of the calculation, so variables are immutable (stateless)
The benefits of pure functions
  • cacheable

    • Because the same input will always have the same output for pure functions, the results of pure functions can be cached

    • Create your own memoize function

      function memoize(fn){
      	let cache = {};
          return function(){
              let key = JSON.stringify(arguments);
              cache[key] = cache[key] || f.apply(fn,arguments);
              return cache[key]
          }
      }
      Copy the code
  • testable

    • Pure functions make testing easier
  • Parallel processing

    • Parallel manipulation of shared memory data in a multithreaded environment is likely to cause unexpected problems
    • Pure functions do not need to access shared memory data, so they can be run arbitrarily in parallel
Side effects
  • Side effects make a function impure. If the function depends on external state, it cannot guarantee the same output, which can have side effects.

  • Sources of side effects

    • The configuration file
    • The database
    • Get user input
    • .

    All external interactions have the potential for side effects. Side effects are also not suitable for expansion and reuse, and side effects will bring security risks to the program and uncertainty to the program. However, side effects cannot be completely banned, and they should be controlled as far as possible.

Haskell Brooks Curry

The concept of Currying
  • When a function has more than one argument, call it by passing some of the arguments (these arguments never change).
  • It then returns a new function that takes the remaining arguments and returns the result
  • In human terms, a function with n arguments is converted into a function that can be called (n ~ 1) times consecutively, i.efn(x,y,z)Into acurriedFn(x)(y)(z)orcurriedFn(x,y)(z)orcurriedFn(x)(y,z)orcurriedFn(x,y,z)
The Currization function in Lodash
  • _.curry(fn)

    • Function: creates a function that takes one or more arguments from func, executes func and returns the result of execution if all the arguments needed by func are provided, otherwise returns the function and waits for the rest of the arguments to be accepted

    • Parameters: functions that require currization

    • Return value: The currified function

      const _ = require('lodash');
      // The currified function
      function getSum(a,b,c){
          return a + b + c;
      }
      // The currie function
      let curried = _.curry(getSum)
      / / test
      curried(1.2.3);
      curried(1) (2) (3);
      curried(1.2) (3);
      Copy the code
  • Simulate the implementation of _.curry()

    function curry(fn){
        return function curriedFn(. args){
            if(fn.arguments.length > args.length){
                // Call recursively until the number of arguments is equal
                returncurriedFn(... args.concat(Array.from(arguments)))}// call fn with the same number of arguments and parameters
            return fn(...args);
            
        }
    }
    Copy the code
  • conclusion

    • Corrification allows us to pass fewer arguments to a function and get a function that has some fixed arguments memorized, so it’s a kind of caching of function arguments
    • Make the function more flexible and less granular
    • You can convert multivariate functions into unary functions, and you can combine functions to produce powerful functions

Function composition

  • Pure functions and Currization are easy to write onion code h(g(f(x)).

    • If the last element of an array is converted to uppercase:_.toUpper(_.first(_.reverse(array)))
    • Function composition allows us to recombine fine-grained functions to generate a new function
    • Speaking human language is: the function of a single multiple functions, recombination to produce a composite function
    concept
    • Compose: If a function needs to be processed by multiple functions to get the final value, you can combine intermediate functions into a single function
      • Functions are like cleaning the pipes of data, and composition of functions is to connect the pipes and pass the data through the pipes to form the final result
      • Function combinations are executed from right to left by default
    // combine functions
    function compose(f,g){
        return function(x){
            returnf(g(x)); }}function first(arr){
        return arr[0]};function reverse(arr){
        return arr.reverse();
    }
    
    // Execute from right to left
    let last = compose(first,reverse);
    console.log(last([1.2.3.4]))
    Copy the code
  • Function composition in LoDash

    • Flow () : executes from left to right
    • FolwRight () : Executes from right to left, using more
  • Simulate the flowRight that implements LoDash

    // Multiple function combinations
    function compose(. fns){
    	return function(value){
            return fns.reverse().reduce((accValue,curFn) = >{
                return curFn(accValue)
            },value)
        }
    }
    Copy the code
  • The function combination must satisfy associativity:

    • We can combine g with h, we can combine f with g, and it’s the same thing
    // Associativity
    let f = compose(f,g,h)
    let associative = compose(compose(f,g),h) == compose(f,compose(g,h)) // true
    Copy the code
    debugging
    • If you debug the composite function

      const _ = require('lodash');
      
      const trace = _.curry((tag,value) = >{
          console.log(tag,value);
          return value;
      })
      
      const split = _.curry((sep,str) = >_.split(str,sep));
      const join = _.curry((sep,array) = >_.join(array,sep));
      const map = _.curry((fn,array) = >_.map(array,fn));
      
      const f = _.flowRight(join(The '-'),trace('after the map'),map(_.toLower),split(' '));
      
      console.log(f('NEVER SAY DIE'))
      Copy the code
  • lodash/fp

    • Lodash’s FP module provides a functional programming friendly approach to use

    • Provides immutable auto-curried iteratee-first data-last methods

      const fp = require('lodash/fp')
      
      // They are the same
      fp.map(fp.toUpper,['a'.'b'.'c']);
      fp.map(fp.toUpper)(['a'.'b'.'c']);
      
      Copy the code

Point Free

concept

We can define the process of the data as a composition operation independent of the data, without using the number representing the data, as long as the simple operation steps are composed together. Before using this pattern we need to define some auxiliary basic operation functions.

  • There is no need to specify the data to be processed

  • You just need to synthesize the operation

  • You need to define some auxiliary basic operation functions

  • Case presentation

    // Non-point Free mode
    // Hello World => hello world
    function f(wrod){
        return word.toLowerCase().replace(/\s+/g.'_');
    }
    
    // Point Free mode
    const fp = require('lodash/fp');
    
    const f = fp.flowRight(fp.replace(/\s+/g.'_'),fp.toLower)
    Copy the code