-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
JavaScript专题之函数组合 #45
Comments
不觉明厉,成长的路任重道远 |
@liuxinqiong 对呀,我也是这种感叹!😂 |
高阶函数呢? 你有项目是使用函数式编程写的吗? |
@yangchongduo 柯里化就是用高阶函数实现的呀,我没有在项目中用到函数式编程,这主要是因为我对于函数式编程掌握的依然不熟练,对于更深层次的如 Monad 依然没有掌握 |
给个redux中的实现,很简洁:
|
@xuchaobei 感谢补充~ |
@xue1234jun 感谢指出,已经更改~ |
看Learning React时突然想起这个教程,里面有个用ES6语法写的compose函数,想了半天突然发现就是这个教程里的这个概念啊 😎 const compose = (...fns) =>
(arg) =>
fns.reduce(
(composed, f) => f(compose),
arg
) |
const compose = (...fns) => fns.reduce((f, g) => (...args) => f(g(...args))); |
脑袋疼 |
let compose = (...fns) => (arg) => {
return dispatch(0)
function dispatch(index) {
arg = fns[index](arg)
if (index === fns.length - 1) return arg
else return dispatch(++index)
}
} |
看了半天 这个 函数式编程思想很不错 compose结合柯里化很有意思 学习了 |
补充一个非常常见的场景,react中的HOC组合 调用很多HOC时,代码如下: withRoute(observer(inject('Store')(Index))) 可以预想,当HOC更多时会变得非常难以维护,可以用compose进行一定的阅读性提升 const enhance = compose(withRoute, observer, inject('Store'));
enhance(Index); 因为HOC的本质就是接受一个组件并且返回一个组件的函数! 当然如果用装饰器就更方便了~ @inject('Store')
@withRoute
@observer
export default class Index extends Component {
...
...
} |
@HuangQiii 如果使用hooks 就没法用装饰器了 还是老老实实的hoc吧 =。= 悲剧 |
虽然很优雅,但是我觉得要是实际业务中用ramda的话,不熟的人接手会一脸蒙逼啊 |
专题很优秀,学到不少知识,感觉楼主的分享,期待其他分类 |
这篇知识量有点大,在lodash中有类似compose的函数吗 |
const compose = (...args) => value => args.reverse().reduce((acc, fn) => fn(acc), value) |
compose这么写更好些,注意用reduceRight const compose = (...funcs) => {
return (val) => {
return funcs.reduceRight((a, b) => b(a), val);
};
}; |
函数式编程 感觉更适合 用在底层都一些框架 ,库之类的编写上, 对于业务来讲,代码不太好看懂 |
最近这几篇深深的感受到脑子不够用了 |
pointfree这个概念,大佬从哪里看来的,厉害呀 |
感觉从右到左有点反直觉啊。评论里很多 reduce 实现,需要注意处理 this |
|
需求
我们需要写一个函数,输入 'kevin',返回 'HELLO, KEVIN'。
尝试
还好我们只有两个步骤,首先小写转大写,然后拼接字符串。如果有更多的操作,greet 函数里就需要更多的嵌套,类似于
fn3(fn2(fn1(fn0(x))))
。优化
试想我们写个 compose 函数:
greet 函数就可以被优化为:
利用 compose 将两个函数组合成一个函数,让代码从右向左运行,而不是由内而外运行,可读性大大提升。这便是函数组合。
但是现在的 compose 函数也只是能支持两个参数,如果有更多的步骤呢?我们岂不是要这样做:
为什么我们不写一个帅气的 compose 函数支持传入多个函数呢?这样就变成了:
compose
我们直接抄袭 underscore 的 compose 函数的实现:
现在的 compose 函数已经可以支持多个函数了,然而有了这个又有什么用呢?
在此之前,我们先了解一个概念叫做 pointfree。
pointfree
pointfree 指的是函数无须提及将要操作的数据是什么样的。依然是以最初的需求为例:
我们再举个稍微复杂一点的例子,为了方便书写,我们需要借助在《JavaScript专题之函数柯里化》中写到的 curry 函数:
从这个例子中我们可以看到,利用柯里化(curry)和函数组合 (compose) 非常有助于实现 pointfree。
也许你会想,这种写法好麻烦呐,我们还需要定义那么多的基础函数……可是如果有工具库已经帮你写好了呢?比如 ramda.js:
而且你也会发现:
那么使用 pointfree 模式究竟有什么好处呢?
实战
这个例子来自于 Favoring Curry:
假设我们从服务器获取这样的数据:
我们需要写一个名为 getIncompleteTaskSummaries 的函数,接收一个 username 作为参数,从服务器获取数据,然后筛选出这个用户的未完成的任务的 ids、priorities、titles、和 dueDate 数据,并且按照日期升序排序。
以 Scott 为例,最终筛选出的数据为:
普通的方式为:
如果使用 pointfree 模式:
如果直接使用 ramda.js,你可以省去编写基本函数:
当然了,利用 compose,你也可以这样写:
compose 是从右到左依此执行,当然你也可以写一个从左到右的版本,但是从右向左执行更加能够反映数学上的含义。
ramda.js 提供了一个 R.pipe 函数,可以做的从左到右,以上可以改写为:
专题系列
JavaScript专题系列目录地址:https://github.com/mqyqingfeng/Blog。
JavaScript专题系列预计写二十篇左右,主要研究日常开发中一些功能点的实现,比如防抖、节流、去重、类型判断、拷贝、最值、扁平、柯里、递归、乱序、排序等,特点是研(chao)究(xi) underscore 和 jQuery 的实现方式。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: