随着 React 的大火,也让函数式编程越来越受到前端er的关注(React大量借鉴了函数式编程的思想,如一个组件基本就是一个「纯函数」)。
但JS毕竟不同于Lisp或Haskell,函数式编程只是JS具有的一项能力。
在此,将我认为函数式编程对JS开发很有价值的思想梳理一下:
纯函数
即无副作用的函数:
1)不会改变函数实参的值(immutable)。如数组的slice方法便不会改变原数组的值(immutable), 而数组的push方法便会改变原数组的值(mutable)。
2)不会调用外部作用域的变量。
其意义:使得函数与外部解耦,函数的使用更加安全。柯里化
其思想为,任何一个多参的“基础函数”,可以通过闭包等技术将该函数的前几个参数赋值,从而将该函数“赋能”为“定制函数”。
function add(a, b) {
return a + b;
}
// add(2, 5); // 7
// 将其改写为 add(2)(5) // 7
function add(a) {
return b => a + b;
}
add(2)(5); // 7
// add(2)(5)等同于
const add2 = add(2); // add2 便是柯里化后的函数
add2(5);
其意义:大量的“定制函数”,都可通过“基础函数”的柯里化得到,能极大简化代码。
注:函数的柯里化可通过 Lodash 的 _.curry 轻易实现。
-
compose
其思想为将数据依次经过几个函数处理(函数的嵌套),最终输出结果数据。
注:由于 compose 的实现与使用较麻烦,Lodash 的 _.flow 提供了 compose 的功能,且可读性更强,下例以 _.flow + _.curry 实现 compose 的demo:
// 求出 data 中, 年龄在20岁以上,体重最小者:
import _ from 'lodash';
const data = [
{name: 'a', age: 37, weight: 72},
{name: 'b', age: 17, weight: 64},
{name: 'c', age: 24, weight: 89},
{name: 'd', age: 66, weight: 83},
{name: 'e', age: 47, weight: 105},
{name: 'f', age: 18, weight: 61}
];
function filterBy(predicate, data) {
return data.filter(predicate);
}
function sortBy(field, data) {
return data.sort((a, b) => a[field] - b[field]);
}
function head(data) {
return data[0];
}
_.flow([
_.curry(filterBy)(d => d.age > 20), // 筛选 20 岁以上的对象
_.curry(sortBy)('weight'), // 以 weight 进行排序
head // 获得数组第一个元素
])(data); // {name: "a", age: 37, weight: 72}
另外, lodash 可作函数式编程,以上代码,改为 lodash 代码:
// 求出 data 中, 年龄在20岁以上,体重最小者:
import _ from 'lodash';
import fp from 'lodash/fp';
const data = [
{name: 'a', age: 37, weight: 72},
{name: 'b', age: 17, weight: 64},
{name: 'c', age: 24, weight: 89},
{name: 'd', age: 66, weight: 83},
{name: 'e', age: 47, weight: 105},
{name: 'f', age: 18, weight: 61}
];
_.flow([
fp.filter(d => d.age > 20),
fp.sortBy('weight'),
_.head
])(data) // {name: "a", age: 37, weight: 72}
其意义:从 .flow 的每一步中,以函数名便知该步的意图,这便是函数式编程的一大好处——声明式(Declarative)的编程方式。
有了函数式编程的思想,则在开发时,最小的代码单位是“基础函数”,通过 柯里化 + compose(.flow) 使得开发就像“搭积木”一样,通过函数的各种组装,便能组织成完整代码。
综上,开发中,仅使用以上三点,就能带来的好处有:
1,可读性强:声明式(Declarative)使得代码即使没有注释也有很高的可读性(这也是 React 的一大卖点)。
2,代码量少:项目越大,越节省代码量(大量的函数被复用)。
3,代码稳定可靠:纯函数的功劳。
4,容易维护性:符合「单一职能原则」,使得代码的维护与迭代更加容易。