函数式编程

JavaScript函数式编程

函数式编程的基础是一等函数(函数在js中作为一等公民)、作用域(词法作用域,动态作用域)和闭包。
函数式编程的第一个概念是高等函数:高等函数将函数作为参数,或者将函数作为返回值。
高等函数是函数式编程的基础,几乎随处可见高等函数。

由函数构建函数

首先讨论函数的构建。函数式编程通过高等函数和一等函数构建,常用的方法有三种

柯里化

柯里化为每一个逻辑参数返回一个新函数,分为手动柯里化和自动柯里化。

手动柯里化

自己手写函数的柯里化版本,有柯里化方向的选择(向左还是向右)

function div(n ,d) {
  return n / d;
}

function leftCurry(n) {
  return function (d) {
    return n / d;
  }
}

function rightCurry(d) {
  return function (n) {
    return n / d;
  }
}

但这样很麻烦,每个函数都要提供一个柯里化版本

自动柯里化

指我们通过一个curry函数生成一个普通函数的柯里化版本

比如我们可以写这样一个curry2函数做到手动柯里化中的那种效果

function curry2(func) {
  return function (first) {
    return function (second) {
      return func(first, second);
    };
  };  
}

function div(n, d) {
  return n / d;
}

var leftCurry = curry(div);

这样实现的一个leftCurry跟手动柯里化实现的是一模一样的;但是自动柯里化是用过curry函数和div函数构建出leftCurry函数的;这样做也限定了柯里化的方向;我们可以通过再编写一个curry函数使用另外一种方向来解决这个问题。

再说一个自动柯里化的用处。这个柯里化如下:

function curry(func) {
  return function (args) {
    return func(args);
  }
}

直观上看这个柯里化有什么用?为什么不直接使用func(args)呢?

这个柯里化的场景在使用这样的语句时格外有用[11, 11, 11, 11].map(parseInt)时格外有用。这行代码貌似会返回[11, 11, 11, 11],但实际上的返回结果是[11, NaN, 3, 4]

这是为什么呢?我们看了map的源码就能知道,map接收的函数,实际上是一个iteratee(item, index, array),也就是说,这行代码实际运行的是[parseInt(11, 0, array) parseInt(11, 1, array), parseInt(11, 2, array), parseInt(11, 3, array)]

为了避免给这个iteratee传入过多的参数,我们可以通过柯里化返回一个只接受一个参数的函数

[11, 11, 11, 11].parseInt(curry(parseInt)),这样我们就能得到理想的结果[11, 11, 11, 11].

柯里化的缺点

柯里化明显只适合于有限参数的函数;如果函数的参数过多(当然我们杜绝设计这样的函数)或者函数的参数未定,那就不适合用柯里化来构建函数。这时就更适合用partial

partial

bind的实现其实就有partial的写法;因为bind在传递上下文的时候,也是可以传部分参数的。

Function.prototype.bind = function (context) {
  context = Obejct(context) || window;
  // 保存一部分参数
  var args = [].slice.call(arguments, 1);
  // ...其他操作

  return function () {
    // 补全参数
    args = args.concat([].slice.call(arguments));
  }
}

compose

compose就是拼接函数,返回一系列函数组合后的复合函数,好比在数学里, 把函数 f(), g(), 和 h() 组合起来可以得到复合函数 f(g(h()))。

递归

  1. 递归最有名的应用就是深克隆
  2. 递归操作都应该被封装

函数式编程的组成

这里有两个React讲到的概念:纯函数,不变性。

纯函数

什么是纯函数?

  1. 返回结果只由参数决定,不受外部数据的影响
  2. 不改变外部状态
  3. 不受Math.randomDate.now影响,没有this,没有全局变量

纯函数便于函数的组成,有助于消除函数组合出来新的行为正确与否的担忧:纯函数的组合依旧是纯函数。

不变性

js中的String类是最适合说不变性的。字符串类型的变量在调用方法后,返回调用后的值,但字符串本身是没有被改变的。

链式调用

链式调用看underscore_.chain的源码就好。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容