函数式编程?

纯函数

  • 对于相同的输入,输出相同,
  • 没有任何可观察的副作用,也不依赖外部环境的状态,其输出只取决于传入的参数
  • 上述的副作用,比如 array.splice 等会修改原有变量的方法
  • es6 许多方法都是没有副作用,它们会返回一个新的变量,如 filter、slice、reduce 等

使用纯函数的优点:

  • 可以有效降低系统的复杂度
  • 实现可缓存性
1
2
3
4
5
6
import _ from "lodash";
var sin = _.memorize((x) => Math.sin(x));
//第一次计算的时候会稍慢一点
var a = sin(1);
//第二次有了缓存,速度极快
var b = sin(1);

函数的柯里化(curry)

  • 把一个多参函数的单步求值过程,转变成多个单参函数的多步求值过程

    或可简单理解为

  • 传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数
1
2
3
4
5
6
var add = (x) => (y) => x + y;
//试试看
var add2 = add(2);
var add200 = add(200);
add2(2); // =>4
add200(50); // =>250

事实上柯里化是一种“预加载”函数的方法,通过传递较少的参数,得到一个已经记住了这些参数的新函数,某种意义上讲,这是一种对参数的“缓存”,是一种非常高效的编写函数的方法
参考:JavaScript 函数式编程(一)–starkwang

FP 和 PF

FP:function programing 函数式编程

PF:PointFree 风格,是一种函数式编程风格

什么是 Pointfree 风格

封装纯函数的运算过程为一个复合函数,逻辑清晰,风格简洁

下面,我们来看一个示例。

1
var str = "Lorem ipsum dolor sit amet consectetur adipiscing elit";

上面是一个字符串,请问其中最长的单词有多少个字符?
我们先定义一些基本运算。

1
2
3
4
5
6
7
8
9
10
// 以空格分割单词
var splitBySpace = (s) => s.split(" ");
// 每个单词的长度
var getLength = (w) => w.length;
// 词的数组转换成长度的数组
var getLengthArr = (arr) => R.map(getLength, arr);
// 返回较大的数字
var getBiggerNumber = (a, b) => (a > b ? a : b);
// 返回最大的一个数字
var findBiggestNumber = (arr) => R.reduce(getBiggerNumber, 0, arr);

然后,把基本运算合成为一个函数(查看完整代码)。

1
2
3
4
5
6
var getLongestWordLength = R.pipe(
splitBySpace,
getLengthArr,
findBiggestNumber
);
getLongestWordLength(str); // 11

可以看到,整个运算由三个步骤构成,每个步骤都有语义化的名称,非常的清晰。这就是 Pointfree 风格的优势。
Ramda 提供了很多现成的方法,可以直接使用这些方法,省得自己定义一些常用函数

1
2
3
4
5
6
// 上面代码的另一种写法
var getLongestWordLength = R.pipe(
R.split(" "),
R.map(R.length),
R.reduce(R.max, 0)
);

参考:Pointfree 编程风格指南-阮一峰的网络日志

函数式编程工具库

Ramda 介绍–阮一峰

Hello World 从输入 URL 到页面加载的过程

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×