初见函数式编程

在学习 JS 的过程中时常会听到一个名次——“函数式编程”,那么究竟什么是函数式编程,函数式编程又有什么优点,这就在这篇博客进行一个简单的总结吧~

主要内容:

  • 函数式编程的概念
  • 函数式编程的优点与示例

什么是函数式编程

首先,我们放下编程的概念,我们来看函数。

函数的概念来自于数学,数学中的函数 f(x) = y 有一个非常重要的特点对于一个给定的 x,有唯一的 y 与其对应(这就是为什么椭圆曲线不是函数)

然而在编程中,函数并不具有这个特点,举个栗子:

let val = 1
function add(x){
    return x + val
}
console.log(add(1)) // 2
val += 1
console.log(add(1)) // 3
复制代码

可以看到编程中的函数在参数相同的情况下,允许有不同的返回值——只要依赖于函数外部的量

那么当函数依赖于外部的变量(常量不会有这样的问题),并且函数在多处调用,就有可能出现 bug,函数的调用结果可能会和预期结果相去甚远

函数式编程就要求我们规避这样的情况,让所有函数对于相同的输入的返回值相同,这样的特性就叫做引用透明性,这就是函数式编程的核心特性!

一个符合引用透明性的函数的栗子:

function id(x){ return x; }
复制代码

函数式编程带来的优点

在上文中提到过,编程语言中的函数大多是不满足数学中的函数的概念的,so 我们将满足数学函数条件的函数称为“纯函数”

函数式编程的优点大多都来自于纯函数

可测试性

除了测试人员进行的全方位测试外,我们在开发过程中往往要对自己写的代码进行模块测试

在开发中,我受非纯函数迫害已久,由于它依赖了外部变量(比如存储在 localStorage 中的数据)我不得不三番五次去检查这些外部变量是否在某个过程中被改变甚至是删除

let val = 1
function add(x){
    return x + val
}
console.log(add(1)) // 2
// 在未知因素影响下 val被改变
console.log(add(1)) // 预期结果 2,实际输出 emmmmm
复制代码

如果我没有注意外部依赖而是一头扎进函数逻辑里,可能永远都找不到这个bug

代码的并发性

虽然我们都知道 JS 是一门单线程语言(关于JS的执行可以参见->技术总结——JS的执行顺序),但是我们为了提高前端的性能可能会通过 WebWorker 来并发执行多个任务,或者在 Node 环境下 JS 并发执行函数

这个时候就是对非纯函数的一个很大的考验:

let global = "全局变量"
let func1 = ()=>{
    global = "全局变量被改变了"
    // 一些逻辑
}
let func2 = ()=>{
    if(global = "全局变量"){
        return true
    }
}
复制代码

上面的两个函数都依赖于外部的global,当它们并发执行,func1就会对func2产生影响,如果将它们变为纯函数就不会有这样的问题:

let global = "全局变量"
let func1 = (x)=>{
    x = "全局变量被改变了"
    // 一些逻辑
}
let func2 = (x)=>{
    if(x = "全局变量"){
        return true
    }
}
复制代码

函数执行的缓存

当我们的函数都是纯函数,而我们又会多次调用函数,我们就可以对函数对象进行一个缓存

比如我们需要大量计算数字的4次方,我们可以建立一个映射表用来缓存函数的执行结果:

// 映射表
let fourTimesTable = {};
let fourTimes = (x){
    return x*x*x*x
}
// 检查表中是否有 2 的四次方,如果有就返回,如果没有就执行函数避免运算
fourTimesTable.hasOwnProperty(2)?
    fourTimesTable[2]:
    fourTimesTable[2] = fourTimes(2)
复制代码

管道与组合

管道过滤器是一种很经典的设计模式,我们可以将这种模式和函数式编程结合起来

在管道和过滤器软件体系结构中,每个模块都有一组输入和一组输出。每个模块从它的输入端接收输入数据流,在其内部经过处理后,按照标准的顺序,将结果数据流送到输出端,以达到传递一组完整的计算结果实例的目的。

在这种结构中,各模块之间的连接器充当了数据流的导管,将一个过滤器的输出传到下一个过滤器的输入端。所以,这种连接器称为“管道”。

我们也可以将这样的私用运用在函数式编程中,将一个个函数作为过滤器,通过函数的组合,形成一条数据处理的通路:

// 参数累加
function add(...args){
    let result = args.reduce((prev, cur, index, arr)=> {
        return prev + cur;
    })
    return result
}
// 参数累乘
function times(...args){
    let result = args.reduce((prev, cur, index, arr)=> {
        return prev * cur;
    })
    return result
}

let arr1=[1,3,6],arr2=[2,5,21],arr3=[3,7,8,27,4]
// 三组数据,要求组内累乘,然后结果累加
add(times(...arr1),times(...arr2),times(...arr3))
// 三组数据,要求组内累加,然后结果累乘
times(add(...arr1),add(...arr2),add(...arr3))
复制代码

对函数式编程的初探暂止于此,进一步学习后再做总结~

本文同步发布于我的个人博客CSDN掘金

如果有什么问题,意见,建议欢迎评论;如果觉得我写的不错,那就点个赞吧~

转载于:https://juejin.im/post/5ceb99bbf265da1bc41431b6

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值