函数式编程

1. 避免包裹函数

// 这行
ajaxCall(json => callback(json));

// 等价于这行
ajaxCall(callback);

// 那么,重构下 getServerStuff
const getServerStuff = callback => ajaxCall(callback);

// ...就等于
const getServerStuff = ajaxCall // <-- 看,没有括号哦

如果一个函数被不必要地包裹起来了,而且发生了改动,那么包裹它的那个函数也要做相应的变更

httpGet('/post/2', json => renderPost(json));

如果 httpGet 要改成可以抛出一个可能出现的 err 异常,那我们还要回过头去把“胶水”函数也改了。

// 把整个应用里的所有 httpGet 调用都改成这样,可以传递 err 参数。
httpGet('/post/2', (json, err) => renderPost(json, err));

写成一等公民函数的形式,要做的改动将会少得多

httpGet('/post/2', renderPost);  // renderPost 将会在 httpGet 中调用,想要多少参数都行

后一个就显得更加通用,可重用性也更高

// 只针对当前的博客
const validArticles = articles =>
  articles.filter(article => article !== null && article !== undefined),

// 对未来的项目更友好
const compact = xs => xs.filter(x => x !== null && x !== undefined);

2. 纯函数的好处

纯函数是这样一种函数,即相同的输入,永远会得到相同的输出,而且没有任何可观察的副作用。

var xs = [1,2,3,4,5];
// 纯的
xs.slice(0,3); //=> [1,2,3]
xs.slice(0,3); //=> [1,2,3]
xs.slice(0,3); //=> [1,2,3]

// 不纯的
xs.splice(0,3); //=> [1,2,3]
xs.splice(0,3); //=> [4,5]
xs.splice(0,3); //=> []

副作用可能包括…

副作用是在计算结果的过程中,系统状态的一种变化,或者与外部世界进行的可观察的交互

副作用可能包含,但不限于:

  • 更改文件系统
  • 往数据库插入记录
  • 发送一个 http 请求
  • 可变数据
  • 打印/log
  • 获取用户输入
  • DOM 查询
  • 访问系统状态

追求“纯”的理由

可缓存性(Cacheable)

// 下面的代码是一个简单的实现,尽管它不太健壮。
var memoize = function(f) {
  var cache = {};

  return function() {
    var arg_str = JSON.stringify(arguments);
    cache[arg_str] = cache[arg_str] || f.apply(f, arguments);
    return cache[arg_str];
  };
};

值得注意的一点是,可以通过延迟执行的方式把不纯的函数转换为纯函数:它总是会根据相同的输入返回相同的输出:给定了 url 和 params 之后,它就只会返回同一个发送 http 请求的函数。

var pureHttpCall = memoize(function(url, params){
  return function() { return $.getJSON(url, params); }
});

可测试性(Testable)

合理性(Reasonable)

很多人相信使用纯函数最大的好处是引用透明性(referential transparency)。如果一段代码可以替换成它执行所得的结果,而且是在不改变整个程序行为的前提下替换的,那么我们就说这段代码是引用透明的

Leave a Reply

Your email address will not be published. Required fields are marked *