-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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: