函数式编程之 compose 实现

原打算研究下 compose 实现就好了,可是顺藤摸瓜,看到了一个更大的世界。先来看看函数式编程,再来学学 compose 的实现吧。

一、命令式编程 VS 声明式编程

常见的编程范式有:命令式编程(面向过程)、面向对象编程(Class)、声明式编程、函数式编程(声明式编程的一种)等。

为实现 (1+2) * 3 / 4 ,命令式和声明式编程如下:

命令式编程

专注于如何去做的具体过程,为解决某一问题而实现的算法。

a = 1 + 2
b = a * 3
c = b / 4

为了解决问题的一个过程。需要一行行看代码,才能理解要的是什么。

声明式编程

专注于目标,我需要什么。

divide(multiply(add(1, 2), 3), 4)

我需要 add 后的结果 -> multiply 后的结果 -> divide 后的结果。而 ‘‘how’’ 交给具体的函数去做,我们只专注于想要什么。

声明式编程语言,例如 SQL、D3
SQL:我想要一个什么样的关联数据

SELECT * from dogs
INNER JOIN owners
WHERE dogs.owner_id = owners.id

D3:我要的是一个圆,中心是x和y,初始值是0 ,半秒后变换成半径为5

var circles = svg.selectAll('circle')
.data(data)

circles.enter().append('circle')
	.attr('cx', function(d) { return d.x })
	.attr('cy', function(d) { return d.y })
	.attr('r', 0)
	.transition().duration(500)
	.attr('r', 5) 

声明式编程让我们更专注于 “what”, 而不是 “how”,代码看上去更加易读。也有助于我们站在更高层面去解决问题。在合适的场景里,我们可以多去应用声明式编程。

二、函数式编程

强调一对一的映射关系。同一种输入,只会有同一种输出结果。有以下特点:

  • 函数是 “一等公民”:操作的基础是函数,可作为出参入参,给其他函数使用
  • 声明式编程:专注于我要什么,而不是怎么做
  • 惰性执行:只在需要的时候执行,几乎没有无意义中间变量。从头到尾都在写函数
  • 无状态和数据不可变:
    无状态:不依赖外部状态(全局变量、this 指针、IO操作等),同样输入都是同样输出
    数据不可变:不改变原来数据(不修改全局、不修改入参)。想修改一个对象,应该创建新对象去修改。
  • 没有副作用:副作用是随意操纵外部变量,可能导致因为共享状态产生的 bug,却难以寻源。
  • 纯函数:不依赖外部状态(无状态)、没有副作用(数据不变)。便于测试和优化(不互相影响)、便于缓存(一种输入只有一种输出)

三、函数组合 compose

函数式编程中,最不可少的两个操作,便是柯里化和函数组合。这里主要讲讲函数组合。

概念
将多个函数组合成一个去使用。

  • 第一个函数是多元的(接受多个参数),后面的函数都是单元的(接受一个参数)
  • 执行顺序的自右向左的
  • 所有函数的执行都是同步的
let step1 = (val) => val + 1
let step2 = (val) => val + 2
const steps= [step2, step1]
const composeFuc = compose(...steps)
composeFuc(1) // 4: 1+1=2 -> 2+2=4

简单版理解:

const compose = (f, g) => x => f(g(x))

多个参数呢?

成熟版:

function compose(...fn) {
  if (!fn.length) return (v) => v;
  if (fn.length === 1) return fn[0];
  return fn.reduce(
    (pre, cur) =>
      (...args) =>
        pre(cur(...args))
  );
}

分析:

function a() {
    console.log(1);
}
function b() {
    console.log(2);
}
function c() {
    console.log(3);
}

compose(a, b, c)

// 为了得到这种结果 a(b(c()))

// 第一次执行 pre: a, cur: b
d = (...args) => a(b(...args))

// 第二次执行 pre: d, cur: c。 得到 a(b(c()))
(...args) => d(c(...args))  

搭配柯里化使用,效果更加。
柯里化实现:

function curry(fn, ...args) {
  const length = fn.length;
  let allArgs = [...args];
  const res = (...newArgs) => {
    allArgs = [...allArgs, ...newArgs];
    if (allArgs.length === length) {
      return fn(...allArgs);
    } else {
      return res;
    }
  };
  return res;
}

搭配使用:

const split = curry((x, str) => str.split(x));
const join = curry((x, arr) => arr.join(x));
const replaceSpaceWithComma = compose(join(','), split(' ')); // 先传入一个 x,后面再 str 传入。
const replaceCommaWithDash = compose(join('-'), split(','));

replaceSpaceWithComma('a b c') // a,b,c

函数组合的 Debug

const trace = curry((tip, x) => { console.log(tip, x); return x; });
const lastUppder = compose(toUpperCase, head, trace('after reverse'), reverse);

补充:
部分函数应用 vs 柯里化
部分函数应用:固定一部分参数,返回一个更小元的函数(传入更少的参数)。

// 假设一个通用的请求 API
const request = (type, url, options) => ...
// GET 请求
request('GET', 'http://....')
// POST 请求
request('POST', 'http://....')

// 但是通过部分调用后,我们可以抽出特定 type 的 request
const get = request('GET');
get('http://', {..})

参考链接
https://www.cnblogs.com/sunny-lucky/p/14119172.html
https://juejin.cn/post/6844903936378273799#heading-8
https://juejin.cn/post/6968713283884974088

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue 3 支持函数式编程的特性,这意味着你可以在 Vue 组件中使用一些函数式编程的概念和技术。下面是一些与函数式编程相关的特性和用法: 1. 纯函数函数式编程鼓励使用纯函数,这意味着函数的输出只依赖于输入,不会对外部环境产生副作用。在 Vue 组件中,你可以将计算属性、过滤器和方法尽量设计成纯函数,以便更好地进行单元测试和调试。 2. 函数组合:Vue 3 提供了 `compose` 函数,它可以将多个函数组合起来,形成一个新的函数。你可以使用 `compose` 来简化复杂的逻辑处理,提高代码的可读性和可维护性。 3. 高阶组件 (Higher-Order Components):在 Vue 3 中,你可以使用函数式组件 (Functional Components) 来定义高阶组件。函数式组件是一种纯函数,接收一个 props 对象作为参数,并返回一个 VNode。通过使用函数式组件,你可以轻松地将一些常见的逻辑和功能封装成可复用的高阶组件。 4. 不可变数据:函数式编程鼓励使用不可变的数据结构,这意味着数据一旦创建就不能被修改。在 Vue 3 中,你可以使用 `ref` 和 `reactive` 来创建响应式的数据,但是不能直接修改它们的值。如果需要修改数据,应该通过使用特定的方法或函数来产生新的数据。 5. 组件复用:函数式编程鼓励组件的复用性,你可以将一些通用的功能封装成可复用的函数或组件,并在不同的地方进行使用。Vue 3 中的函数式组件和高阶组件是实现组件复用的一种方式。 这些是 Vue 3 中支持函数式编程的一些特性和用法,希望对你有所帮助!如果还有其他问题,请继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值