函数式编程(Functional programming)

函数式编程

为什么要学习函数式编程

  • 函数式编程是随着 React 的流行受到越来越多的关注
  • Vue 3也开始拥抱函数式编程
  • 函数式编程可以抛弃 this
  • 打包过程中可以更好的利用 tree shaking 过滤无用代码
  • 方便测试、方便并行处理
  • 有很多库可以帮助我们进行函数式开发:lodash、underscore、ramda
// 求和
// 非函数式
let num1 = 1
let num2 = 2
let sum = num1 + num2
console.log(sum)

// 函数式
function add (n1, n2) {
    return n1 + n2
}
let sum = add(1, 2)
console.log(sum)
// 函数式这个例子就是表示对运算过程进行抽象,另外函数式编程中的函数指的不是程序中的函数(方法),而是数学中的函数即映射关系,并且要求相同的输入始终要有相同的输出

函数式编程的前置知识

  • 函数可以存储在变量中
  • 函数作为参数
  • 函数作为返回值
  • 可以把函数作为参数传递给另一个函数(比如数组的 forEach 方法,让我们举个例子)
// 模拟 forEach
function forEach(arr, fn) {
    for(let i = 0; i < arr.length; i++) {
        fn(arr[i])
    }
}
// 测试
let arr = [1, 2, 3, 4]
forEach(arr, function (item) {
    console.log(item)
})
// 结果 1 2 3 4
  • 函数作为返回值
function makeFn () {
    let msg = 'Hello'
    return function () {
        console.log(msg)
    }
}

const fn = makeFn()
fn()
// 结果 Hello

  • 可以在另一个作用域中调用一个函数的内部函数并访问到该函数的作用域中的成员。
  • 本质:函数在执行的时候会放到一个执行栈上当函数执行完毕之后会从执行栈上移除,但是
    堆上的作用域成员因为被外部引用不能释放,因此内部函数依然可以访问外部函数的成员

函数式编程的核心概念

  • slice 返回数组中的指定部分,不会改变原数组(纯函数)
  • splice 对数组进行操作返回该数组,会改变原数组
function memoize(f) {
    let cache = {}
    return function () {
        let key = JSON.stringify(arguments)
        cache[key] = cache[key] || f.apply(f, arguments)
        return cache[key]
    }
}
function getSum (a, b, c) {
    return a + b + c
}

function curry (func) {
    return function curriedFn(...args) {
        // 判断实参和形参的个数
        if(args.length < func.length) {
            return function () {
                return curriedFn(...args.concat(Array.from(arguments)))
            }
        }
        return func(...args)
    }
}

const curried = curry(getSum)

console.log(curried(1, 2, 3))
console.log(curried(1)(2, 3))
console.log(curried(1, 2)(3))
// 6 6 6
  • 柯里化可以让我们给一个函数传递较少的参数得到一个已经记住了某些固定参数的新函数
  • 这是一种函数参数的缓存
  • 让函数变的更灵活,让函数的粒度更小
  • 可以把多元函数转换成一元函数,可以组合使用函数产生强大的功能
  • 如果一个函数要经过多个函数处理才能得到最终值,这个时候可以把中间过程的函数合并成一个函数
  • 函数就像是数据的管道,函数组合就是把这些管道连接起来,让数据穿过多个管道形成最终结果
  • 函数组合默认是从右到左执行
  • 举个例子
// 组合函数
function compose (f, g) {
    return function(value) {
        return f(g(value))
    }
}

function reverse (array) {
    return array.reverse()
}

function first (array) {
    return array[0]
}

const last = compose(first, reverse)
console.log(last([1, 2, 3, 4]))
// 结果 4
————————

Functional programming

Why learn functional programming

  • With the popularity of react, functional programming has attracted more and more attention
  • Vue 3 is also embracing functional programming
  • Functional programming can abandon this
  • In the packaging process, we can make better use of tree shaking to filter useless code
  • Convenient for testing and parallel processing
  • 有很多库可以帮助我们进行函数式开发:lodash、underscore、ramda
// 求和
// 非函数式
let num1 = 1
let num2 = 2
let sum = num1 + num2
console.log(sum)

// 函数式
function add (n1, n2) {
    return n1 + n2
}
let sum = add(1, 2)
console.log(sum)
// 函数式这个例子就是表示对运算过程进行抽象,另外函数式编程中的函数指的不是程序中的函数(方法),而是数学中的函数即映射关系,并且要求相同的输入始终要有相同的输出

Pre knowledge of functional programming

  • Functions can be stored in variables
  • Function as parameter
  • Function as return value
  • You can pass a function as an argument to another function (such as the foreach method of an array, let’s take an example)
// 模拟 forEach
function forEach(arr, fn) {
    for(let i = 0; i < arr.length; i++) {
        fn(arr[i])
    }
}
// 测试
let arr = [1, 2, 3, 4]
forEach(arr, function (item) {
    console.log(item)
})
// 结果 1 2 3 4
  • Function as return value
function makeFn () {
    let msg = 'Hello'
    return function () {
        console.log(msg)
    }
}

const fn = makeFn()
fn()
// 结果 Hello

  • You can call an internal function of a function in another scope and access members in the scope of the function.
  • Essence: when a function is executed, it will be placed on an execution stack. When the function is executed, it will be removed from the execution stack, but
    Scope members on the heap cannot be released because they are externally referenced, so internal functions can still access members of external functions

The core concept of functional programming

  • Slice returns the specified part of the array without changing the original array (pure function)
  • Splice operates on the array and returns the array, which will change the original array
function memoize(f) {
    let cache = {}
    return function () {
        let key = JSON.stringify(arguments)
        cache[key] = cache[key] || f.apply(f, arguments)
        return cache[key]
    }
}
function getSum (a, b, c) {
    return a + b + c
}

function curry (func) {
    return function curriedFn(...args) {
        // 判断实参和形参的个数
        if(args.length < func.length) {
            return function () {
                return curriedFn(...args.concat(Array.from(arguments)))
            }
        }
        return func(...args)
    }
}

const curried = curry(getSum)

console.log(curried(1, 2, 3))
console.log(curried(1)(2, 3))
console.log(curried(1, 2)(3))
// 6 6 6
  • Coriolism allows us to pass fewer parameters to a function and get a new function that has remembered some fixed parameters
  • This is a cache of function parameters
  • Make the function more flexible and make the granularity of the function smaller
  • It can convert multivariate functions into univariate functions, and can combine functions to produce powerful functions
  • If a function needs to be processed by multiple functions to get the final value, the functions of the intermediate process can be combined into one function at this time
  • Functions are like pipelines of data. Function combination is to connect these pipelines and let the data pass through multiple pipelines to form the final result
  • Function combinations are executed from right to left by default
  • for instance
// 组合函数
function compose (f, g) {
    return function(value) {
        return f(g(value))
    }
}

function reverse (array) {
    return array.reverse()
}

function first (array) {
    return array[0]
}

const last = compose(first, reverse)
console.log(last([1, 2, 3, 4]))
// 结果 4