前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2023年再看函数式编程

2023年再看函数式编程

作者头像
星宇大前端
发布2023-11-30 09:15:43
1260
发布2023-11-30 09:15:43
举报
文章被收录于专栏:大宇笔记大宇笔记

2017年我写过一篇文档关于函数式编程,那是主要用的还是OC 语言。6年过去了再看函数式编程感觉当时还是青涩。 《iOS 面向函数编程的理解》

最初接触函数式编程还是Rx 系列响应式的概念带来的,这么多年用过Rxswift,Rxjs ,一直理解不够深刻。 React 带来的hooks, 官方概念是利用函数式编程方式,更好的组合,开发和测试。但是还是觉得不够深刻,又看了些资料,梳理下自己的理解,重点关注react 中的提现。

概念

函数式编程是种编程方式,它将电脑运算视为函数的计算。函数编程语言最重要的基础是λ演算(lambda calculus),而且λ演算的函数可以接受函数当作输入(参数)和输出(返回值)。

除了函数式编程方式,还有:

  1. 面向对象编程
  2. 面向过程编程
  3. 命令式编程

纯函数

纯函数是指在函数的执行过程中,不会对程序的状态进行任何改变,也不会对外部环境产生任何副作用,即只依赖于其输入参数,而不依赖于任何外部变量或状态的函数。

纯函数的特征

1、相同的输入总是产生相同的输出,即函数的输出只由输入决定,不受外部状态或副作用的影响。

2、函数对外部状态没有依赖,也不会改变外部状态,即不会对程序的其他部分产生任何副作用。

3、函数不会修改传入的参数,而是返回一个新的值,保持输入参数的不可变性。

4、函数的执行过程对于调用者来说是透明的,即调用者不需要了解函数的内部实现细节,只需要关注输入和输出。

举例

纯函数:

代码语言:javascript
复制
function sum(a,b) {
  return a + b;
}

非纯函数(引入外部变量):

代码语言:javascript
复制
var c = 0
function sum(a,b) {
  return a + b + c;
}

非纯函数(副作用):

代码语言:javascript
复制
function sum(a,b) {
  console.log(a);
  return a + b ;
}
纯函数的优势
  • 可靠,输出是由输入决定
  • 可测试性强
  • 可缓存
  • 没有副作用,利于代码维护重构以及并行处理

JS 中函数编程思想应用

函数编程思想,函数是一等公民,输入沿着函数管道组合产生想要的结果。

下面这个例子利用map、filter、reduce 等函数对入参一个对象数组进行加工,这是一个简单的函数式编程的思想应用,array 每次经过纯函数的加工,返回结果作为输出再次加工。

代码语言:javascript
复制
let arr  = [{key: 'a', value: 1},{key: 'b', value: 2},,{key: 'c', value: 3}]
arr.map((item)=>item.value).filter((item)=>item !==2).reduce((t,i)=>t+i,0)

一个输入到达终点的路径很多,路径都是一个个函数。所以函数之间的调用关系也是非常重要的优化手段。

函数柯里化

定义:把接收多个参数的函数,转成接收单一参数的函数,并且返回余下参数的函数的过程就叫做函数柯里化

举例
代码语言:javascript
复制
// 正常函数
function add(a, b){
   return a + b
}
 
add(1, 2)
 
// 转成柯里化函数
function add(a){
    return function(b){
        return a + b
    }
}
 
add(1)(2)
为什么要柯里化

存在即合理,柯里化的使用场景是哪些呢?

先简单的变化一下上面的例子:

代码语言:javascript
复制
// 正常函数
function add(a, b){
   return a + b
}
 
add(1, 2)
 
// 转成柯里化函数
function add(a){
    return function(b){
        return a + b
    }
}
 
let f1 = add(1)
let add2 = f1(2)
let add3 = f1(3)

这样大概可以看出来柯里化的意义,但是场景不是很合理。下面是一个正则的例子:

代码语言:javascript
复制
// 正常正则验证字符串 reg.test(txt)

// 函数封装后
function check(reg, txt) {
    return reg.test(txt)
}

// 即使是相同的正则表达式,也需要重新传递一次
console.log(check(/\d+/g, 'test1')); // true
console.log(check(/\d+/g, 'testtest')); // false
console.log(check(/[a-z]+/g, 'test')); // true

// Currying后
function curryingCheck(reg) {
    return function (txt) {
        return reg.test(txt)
    }
}

// 正则表达式通过闭包保存了起来
var hasNumber = curryingCheck(/\d+/g)
var hasLetter = curryingCheck(/[a-z]+/g)

console.log(hasNumber('test1')); // true
console.log(hasNumber('testtest'));  // false
console.log(hasLetter('21212')); // false

上面的示例是一个正则的校验,正常来说直接调用 check 函数就可以了,但是如果我有很多地方都要校验是否有数字,其实就是需要将第一个参数 reg 进行复用,这样别的地方就能够直接调用 hasNumber、hasLetter 等函数,让参数能够复用,调用起来也更方便。

柯里化封装
代码语言:javascript
复制
// 支持多参数传递
function currying(fn, ...args) {
 
    var self = this
    var len = fn.length;
    var args = args || [];
 
    return function() {
        var _args = Array.prototype.slice.call(arguments);
        Array.prototype.push.apply(args, _args);
 
        // 如果参数个数小于最初的fn.length,则递归调用,继续收集参数
        if (_args.length < len) {
            return currying.call(self, fn, _args);
        }
 
        // 参数收集完毕,则执行fn
        return fn.apply(this, _args);
    }
}
compose 函数

compose 函数可以接收多个独立的函数作为参数,然后将这些函数进行组合串联,最终返回一个“组合函数”。

compose 函数的实现:

代码语言:javascript
复制
function compose(...funcs) {
  if (funcs.length === 0) {
      return arg => arg
  }
  if (funcs.length === 1) {
      return funcs[0]
  }
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

举例说明:

代码语言:javascript
复制
const add = (a) => a + 1
const mul = (a) => a * 10
const f = compose(add, mul)
console.log(f(1))

结果: 11

这个无需多解释,就是把函数由右向左执行,

pipe 函数
代码语言:javascript
复制
function compose(...funcs) {
  if (funcs.length === 0) {
      return arg => arg
  }
  if (funcs.length === 1) {
      return funcs[0]
  }
  return funcs.reduceRight((a, b) => (...args) => a(b(...args)))
}

举例说明:

代码语言:javascript
复制
const add = (a) => a + 1
const mul = (a) => a * 10
const f = compose(add, mul)
console.log(f(1))

结果: 20

我理解,柯里化和组合、pipe 应该会结合理解使用。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-11-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 概念
  • 纯函数
    • 举例
      • 纯函数的优势
      • JS 中函数编程思想应用
        • 函数柯里化
          • 举例
            • 为什么要柯里化
              • 柯里化封装
                • compose 函数
                  • pipe 函数
                  相关产品与服务
                  腾讯云服务器利旧
                  云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档