函数式编程(Functional Programming),又称为泛函编程,是一种编程范式。早在很久以前就提出了函数式编程这个概念了,而后面一直长期被面向对象编程所统治着,最近几年函数式编程又回到了大家的视野中,JavaScript是一门以函数为第一公民的语言,必定是支持这一种编程范式的,下面就来谈谈JavaScript函数式编程中的核心概念纯函数、柯里化以及组合函数。
对于纯函数的定义,维基百科中是这样描述的:在程序设计中,若函数符合以下条件,那么这个函数被称之为纯函数。
对以上描述总结就是:
上面提到了一个词叫“副作用”,那么什么是副作用呢?
编写一个求和的函数sum,只要我们输入了固定的值,sum函数就会给我们返回固定的结果,且不会产生任何副作用。
function sum(a, b) { return a + b } const res = sum(10, 20) console.log(res) // 30以下的sum函数虽然对于固定的输入也会返回固定的输出,但是函数内部修改了全局变量message,就认定为产生了副作用,不属于纯函数。
let message = 'hello' function sum(a, b) { message = 'hi' return a + b }在JavaScript中也提供了许多的内置方法,有些是纯函数,有些则不是。像操作数组的两个方法slice和splice。
slice方法就是一个纯函数,因为对于同一个数组固定的输入可以得到固定的输出,且没有任何副作用;
const nums = [1, 2, 3, 4, 5] const newNums = nums.slice(1, 3) console.log(newNums) // [2, 3] console.log(nums) // [ 1, 2, 3, 4, 5 ]splice方法不是一个纯函数,因为它改变了原数组nums;
const nums = [1, 2, 3, 4, 5] const newNums = nums.splice(1, 3) console.log(newNums) // [ 2, 3, 4 ] console.log(nums) // [ 1, 5 ]对于柯里化的定义,维基百科中是这样解释的:
总结:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩余的参数的过程就称之为柯里化。
编写一个普通的三值求和函数:
function sum(x, y, z) { return x + y + z } const res = sum(10, 20, 30) console.log(res) // 60将以上求和函数柯里化得:
使用ES6箭头函数简写为:
const sum = x => y => z => x + y + z让函数的职责更加单一。柯里化可以实现让一个函数处理的问题尽可能的单一,而不是将一大堆逻辑交给一个函数来处理。
将上面的三值求和函数增加一个需求,在计算结果之前给每个值加上2,先看看不使用柯里化的实现效果:
function sum(x, y, z) { x = x + 2 y = y + 2 z = z + 2 return x + y + z }柯里化的实现效果:
function sum(x) { x = x + 2 return function(y) { y = y + 2 return function(z) { z = z + 2 return x + y + z } } }很明显函数柯里化后,让我们对每个参数的处理更加单一
提高函数参数逻辑复用。同样使用上面的求和函数,增加另一个需求,固定第一个参数的值为10,直接看柯里化的实现效果吧,后续函数调用时第一个参数值都为10的话,就可以直接调用sum10函数了。
function sum(x) { return function(y) { return function(z) { return x + y + z } } } const sum10 = sum(10) // 指定第一个参数值为10的函数 const res = sum10(20)(30) console.log(res) // 60测试:
function sum(x, y, z) { return x + y + z } const curryingSum = autoCurrying(sum) const res1 = curryingSum(10)(20)(30) const res2 = curryingSum(10, 20)(30) const res3 = curryingSum(10)(20, 30) const res4 = curryingSum(10, 20, 30) console.log(res1) // 60 console.log(res2) // 60 console.log(res3) // 60 console.log(res4) // 60组合函数(Compose Function)是在JavaScript开发过程中一种对函数的使用技巧、模式。对某一个数据进行函数调用,执行两个函数,这两个函数需要依次执行,所以需要将这两个函数组合起来,自动依次调用,而这个过程就叫做函数的组合,组合形成的函数就叫做组合函数。
需求:对一个数字先进行乘法运算,再进行平方运算。
一般情况下,需要先定义两个函数,然后再对其依次调用:
function double(num) { return num * 2 } function square(num) { return num ** 2 } const duobleResult = double(10) const squareResult = square(duobleResult) console.log(squareResult) // 400实现一个组合函数,将duoble和square两个函数组合起来:
function composeFn(fn1, fn2) { return function(num) { return fn2(fn1(num)) } } const execFn = composeFn(double, square) const res = execFn(10) console.log(res) // 400实现一个自动组合函数的函数:
function autoComposeFn(...fns) { // 1.拿到需要组合的函数个数 const fnsLen = fns.length // 2.对传入的函数进行边界判断,所有参数必须为函数 for (let i = 0; i < fnsLen; i++) { if (typeof fns[i] !== 'function') { throw TypeError('The argument passed must be a function.') } } // 3.定义一个组合之后的函数 function composeFn(...args) { // 3.1.拿到第一个函数的返回值 let result = fns[0].apply(this, args) // 3.1.判断传入的函数个数 if (fnsLen === 1) { // 如果传入的函数个数为一个,直接将结果返回 return result } else { // 如果传入的函数个数 >= 2 // 依次将函数取出进行调用,将上一个函数的返回值作为参数传给下一个函数 // 从第二个函数开始遍历 for (let i = 1; i < fnsLen; i++) { result = fns[i].call(this, result) } // 将结果返回 return result } } // 4.将组合之后的函数返回 return composeFn }测试:
function double(num) { return num * 2 } function square(num) { return num ** 2 } const composeFn = autoComposeFn(double, square) const res = composeFn(10) console.log(res) // 400
出处:https://www.cnblogs.com/MomentYY/p/15916974.html