2017-08-30读书笔记(函数式编程之Pointfree)

今天看的是函数式编程的相关文章,之前虽然没接触过函数式编程,但是这并不能阻止我们读文章啊。

文章是这篇 Pointfree Javascript

首先肯定先来理解一下标题的意思,然后在阮一峰的博客中找到了这个

Pointfree:不使用所要处理的值,只合成运算过程。中文可以译作"无值"风格。

文章在一开始的时候先抛出了两段代码,代码如下:

// imperative style
var getAdminEmails = function(users) {
  var emails = [];
  for (var i = 0; i < users.length; i++) {
    if (users[i].role === 'admin') {
      emails.push(users[i].email);
    }
  }
  return emails;
}
var getAdminEmails = users =>
    users
      .filter(u => u.role === 'admin')
      .map(u => u.email);

大家可以思考一下这两段代码的区别。

第一段代码的逻辑是我们大多数人在写代码的时候会使用的,先声明一个空的数组,然后再去逐个比对,是不是admin的身份。如果是,就讲这个邮箱,放入数组中。最后返回数组。

而第二段代码的逻辑是根据正常的思维逻辑来写的。它先拿到所有的user,然后使用js原生的filter来取出所有的role是admin的user,最后返回这些user的email。

第二段代码的风格的一个优点是函数的代码更接近函数的描述。这使得它更容易理解和理解它。当其他人来研究你写的新的代码的时候,能够快速了解写了什么、运行程序的时候发生了什么。

但是这第二段代码不是Pointfree的最终想要得到的代码,于是下面又附上了作者想要得出最终想要的代码的思考过程。

作者想了一下,最好我只要声明一下这个函数就能得到结果。

var getAdminEmails = compose(getTheEmailsOf, onlyTheAdminRoleUsers);

于是作者开始实现这两个函数,最终的结果是这样。

作者先大致的介绍了一下需要使用什么基本方法。(其中compose和map是有原生方法的,但作者应该只是想大致介绍一下)

var compose = (f, g) => x => f(g(x));

var prop = p => x => x[p];

var map = f => list => list.map(f);

// which lead to:
var getTheEmailsOf = map(prop('email'));

然后是进一步的封装。

var propEq = v => p => obj =>
  prop(p)(obj) === v;

var filter = f => list =>
  list.filter(f);

var onlyTheAdminRoleUsers =
  filter(propEq('admin')('role'));

最后是需要的函数的声明。

var getAdminEmails = compose(
  map(
    prop('email')),
  filter(
    propEq('admin')('role')));

这就是所谓的Pointfree编程或tacit编程。这个版本完全是由其他的较小、可复用的功能组成的。这些功能不仅可以帮助我们快速完成下一个功能,而且可以帮助我们更快地理解所有的功能。当你知道什么是prop函数后,会觉得prop('something')比obj => obj.something好理解多了。

总结

Pointfree编程就是通过组合使用较小、通用、定义良好且经过良好测试的功能来构建所需的功能进行编程的方法。

也不必担心临时变量,因为他会使得代码更容易理解,更难以引入错误。此外,由于代码的段落较小,使得它更容易理解、更方便测试,这使它更可靠。

当然这不是一个万金油,因为很多时候,会存在一个完全无关的功能。我发现它的主要弱点在于函数具有多个参数的时候。很多时候它会导致有一大部分non Pointfree的代码。但是总体来说,利大于弊。

你可能感兴趣的:(2017-08-30读书笔记(函数式编程之Pointfree))