Why do we do functional programming now?

  • Functional programming is getting more attention with the popularity of React
  • Vue3 is also embracing functional programming
  • Functional programming can also discard this
  • The packaging process makes better use of Three Shaking to filter out useless code
  • Convenient for testing and parallel processing
  • There are many libraries to help us with functional development: Lodash, underscore, Ramda

What is functional programming

Functional programming (FP), FP is one of the programming paradigms, we often hear of programming and procedural programming, object-oriented programming.

  • The way of thinking of object-oriented programming is to abstract the things in the real world into the classes and objects in the program world, and demonstrate the connection of things and events through encapsulation, inheritance and polymorphism.
  • The way of thinking about functional programming: Abstracting things and their relationships from the real world to the program world

Understanding of functional programming thinking

  • The essence of the program: according to the input of a certain operation to obtain the corresponding output, program development involves many functions with input and output

  • X ->f(relation, mapping)->y,y=f(x), input x, through some relation to get the result y, here the relation f is our operation (that is, the function of functional programming), through f(x) get y;

  • A function in functional programming is not a function (method) in a program, but a function (mapping) in mathematics, for example: y=sin(x), the relationship between x and y

  • “The same input always gets the same output” (pure function)

  • Conclusion: Functional programming is used to describe the mapping between data (functions), the abstraction of its data operation processCopy the code

The difference between functional programming and object-oriented programming

  • From the way of thinking, object-oriented programming is the abstraction of things, and two-function programming is the abstraction of operation processCopy the code

The Function is First class citizen: MDN first-class Function

First-class citizens can be: functions can be stored in variables; Function as argument; Function as return value; For example, strings are first-class citizens in almost all programming languages. Strings can be used as function arguments, function return values, and assigned to variables.

In JavaScript, a Function is just an “ordinary object” (via new Function ()), we can store the Function in a variable/array, and it can be used as an argument and return value to another Function, We can even pass new Function (alert (‘ 1 ‘)) while the program is running, so functions in JavaScript are first-class citizens.

To construct a new function;

  • Assign a function to a variable
Let fn = function() {console.log('Hello first-class function ')} fn() const Blogcontroller = {index(posts) {return views.index (posts)} // The index method has the same form as the internal call method, with the same argument and return value; A function contains a function of the same form, Show (post) {return views.show (post)}, create(attrs) {return db.create (attrs)}, update (post, Attrs) {return db.update (post, attrs)}, destroy(post) {return db.destroy (post)}} Const Blogcontroller = {index: views.index // Copy the method itself show: views.show create: Db.create update: Db.update destroy: Db.destroy }Copy the code

Higher-order functions

Concept: higher-order functions can pass “functions as arguments” to another function; You can think of a function as a “return result” of another function

Higher-order functions are used to abstract the general problem higher-order functions —- as arguments; With functions as arguments, arguments become more flexible, and the method forEach calls the function regardless of how the function is implemented;

Functions passed as arguments

Analog forEach: Iterates through each number in the array and returns each item in the array

For example: function parameters: 2 parameters, the first parameter first pass an array, the second parameter, after traversing the array, each array processing operation is different, the content is changed

function forEach( array, fn) { for( let i =0; i< array.length; ForEach (arr,function(item){console.log(item) {if (arr,function(item){console.log(item)){if (arr,function(item){console.log(item)) } function fliter(arr, fn) {let results = [] // for(let I =0; i< arr.length; I ++){if(fn(arr[I])){results.push(arr[I])}} return results} let arrFliter= [2,1,56,8] let f = Fliter (arrFliter, function (item){return item % 2 == 0}) console.log(' filter result ',f)Copy the code

Function as a return value

The higher-order function —–, as the return value, is the function that generates a function

*/ function makeFn() {let MSG = 'Hello MSG 'return function () {console.log(MSG)}} const fn = MakeFn ()() makeFn()() makeFn()() Function once (fn) {let done = false //fn does not return function () {if(! Done) {done = true fn. Apply (this,arguments)}}} // test let pay = once(function (money) {console.log(' pay: ${money} RMB`) }) pay(5) pay(5) pay(5)Copy the code

The meaning of using higher-order functions

  • Abstraction can help us mask the details and focus only on our goals
  • Higher-order functions are used to “abstract generic” problems

Higher-order functions: forEach filter is shown in the preceding example

Commonly used higher-order functions

ForEach, map, filter, every, some, find/findIndex, reduce, sort

// Use the same high-order function: Map every some // map: iterates over the elements of the array and processes each item, Const map = (array, Fn) => {let results = [] // New array for (let value of array) {results.push(fn(value))} return results [1,2,34,5,4] arrMap = map(arr, v => v*v) console.log('map',arrMap) Const every = (array, fn) => {let result = true for(let value of array) {result = fn(value) if(! Result) {break}} return result} // test every let arrE = [122,33,11,14] let r = every(arrE, V => v>10) console.log('every', r) //some Fn) => {let result = false for(let value of array) {result = fn(value) if(result) {break}} return result} // test Let arrSome = [1,3,5,9] let sr = some(arrSome, v=>v % 2 === = 0) console.log('some', sr)Copy the code

closure

Concept: Closure functions are bundled together with references to other surrounding states (lexical context) to form closures. You can call an inner function of a function from another scope and access members of that function’s scope,

We can call the inner function of manFn() in another scope. When we call this inner function, we can access the inner member of manFn()

Function makeFn() {let MSG = 'Hello MSG 'return function () {console.log(MSG)}} Const fn = makeFn() fn() const fn = makeFn()Copy the code

The nature of closures

Functions are placed on an execution stack at execution time and removed from the stack when the function completes execution, but the 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 case

<! DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta Name = "viewport" content = "width = device - width, initial - scale = 1.0, the maximum - scale = 1.0, the minimum - scale = 1.0, Word-wrap: break-word! Important; word-wrap: break-word! Important; "> </head> <body> <script> 3000) // getSalary(15000, Function makeSalary(base) {return function (performance) {return base + performance}}  let salaryLever1 = makeSalary(12000) let salaryLever2 = makeSalary(15000) console.log(salaryLever1(2000)) console.log(salaryLever2(2000)) </script> </body> </html>Copy the code

Pure functions

The concept of pure functions

  • The same input will always get the same output, without any observable side effects
  • A pure function is like a function in mathematics, y = f(x).
  • Functional programming does not preserve the middle of the calculation, so variables are immutable (stateless)
  • We can hand off the results of one function to another
  • Lodash is a library of pure functions that provides methods for operating on arrays, numbers, objects, strings, functions, and more
  • Arrays of slice and splice are pure and impure functions, respectively
    • 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
Let array = [1,2,34,5] console.log(array.slice(0,3)) // does not change the original array Log (array.slice(0,3)) console.log(array.slice(0,3)) console.log(array.splice(0,3)) Return a new array console.log(array.splice(0,3)) console.log(array.splice(0,3))Copy the code

lodash

// initialize, package.json npm init -y ===> npm i lodash // first lasr toUpper reverse each includes find findeIndex const _ = require('lodash') const array = ['jack', 'tom', 'lucy', 'kate'] console.log(_.first(array)) console.log(_.last(array)) console.log(_.toUpper(_.first(array))) console.log(_.reverse(array)) const r = _.each(array, (item, index) =>{ console.log(item, index) }) console.log(r)Copy the code

The benefits of pure functions

  • Cacheable: Because pure functions always have the same result on the same input, they can be cached
// memory function const _ = require('lodash') function getArea() {return math.pi *r*r} let getAreaWithMemory = _. Memoize (getArea) Console. log(getAreaWithMemory(4)) // Fetch data from cache console.log(getAreaWithMemory(4)) console.log(getAreaWithMemory(4)) Function memoize (f) {return function () {let key = json.stringify (arguments) cache[key] = cache[key] || f.apply(f, arguments) return cache[arg_str] } }Copy the code
  • Testable: Pure functions make testing easier

  • Parallel processing

    • Parallel manipulation of shared memory data in a multi-line processing environment is likely to cause unexpected problems
    • Pure functions do not require shared memory data, so they can be run arbitrarily in parallel

Side effects of pure functions

  • Pure functions: For the same input you always get the same output without any observable side effects
Function checkAge (age) {return age >= mini} Function checkAge (age) {let mini = 18 return age >= mini} function checkAge (age) {let mini = 18 return age >= mini}Copy the code

Side effects make a function impure (e.g., global variables). Pure functions return the same output based on the same input, and can have side effects if the function depends on external states that cannot guarantee the same output.

Sources of side effects:

  • The configuration file
  • The database
  • Get user input

All “external interactions” are likely to bring “side effects”, which also reduce the generality of the method and make it unsuitable for expansion and reuse. Meanwhile, 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 much as possible.

Currie,

Using Kerrization to solve the previous case can only hardcode the problem

Function checkAge(age) {let min = 18 return age >= min} // // function checkAge(min, Age) {return age >= min} console.log(checkAge(18,20)) console.log(checkAge(18,24)) console.log(checkAge(22,24)) // currified function checkAge(min) { return function(age) { return age >= min } } let check18 = checkAge(18) let check20 = CheckAge (20) console.log(check18(20)) console.log(check20(22)) // ES6 optimization let checkAge = min => (age => age >= min) let check22 = checkAge(22) console.log(check22(20))Copy the code

Currie,

  • When a function has more than one argument it is called by passing part of the argument (which will never change) and then returns a new function that takes the rest of the argument and returns the result

The Currization function in Lodash

  • _curry(func)
    • Function: creates a function that takes one or more arguments from func, executes func if all the arguments needed by func are provided and returns the result of execution, 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') // function getSum(a, b, C) {return a + b + c} const curried = _. Curry (getSum) // takes all arguments console.log(curried(1,2,3)) // Accepts some arguments, returns a new function, waits to receive the remaining arguments console.log(caches(1)(2,3)) console.log(curried(1,2)(3))Copy the code

case

// Corrification case: // Determine if a string is empty, or extract all empty characters from the string, Match const _= require('lodash') // 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('1234abcd'))  filter const filter = _.curry(function(func, array) { return array.filter(func) }) console.log(filter(haveSpace, ['John Conner', 'John_Donner'])) // Filter array whitespace, Filter optimization const findSpace = filter(haveSpace) console.log(findSpace(['John Conner', 'John_Donner']))Copy the code

Simulate the method of implementing Curry in Lodash

// const _= require('lodash') // function getSum(a, b, C) {return a + b + c} // const curried = _. Curry (getSum) // Lodash parameter const curried = curry(getSum) // In custom curry // accepts all arguments console.log(curried(1,2,3)) // accepts some arguments, returns a new function, waits to receive the remaining arguments console.log(caches(1)(2,3)) Console. log(curried(1,2)(3)) function curry(func){return function curriedFn(... Args){if(args. Length < func.length){return function () {return curriedFn(... Args. concat(array. from(arguments)))}} // Return func(... args) } }Copy the code

Corrified summary

  • Corrification allows us to pass in fewer arguments to a function and get a new function that has memorized some of the fixed arguments
  • This is a function parameter program
  • Let’s make the function more verbose, let’s make the function less granular
  • You can convert a multivariate function into a unary function, and you can combine functions to produce powerful effects