JS函数式编程小记

JS函数式编程思想

  • 维基百科定义:函数式编程(英语:functional programming),又称泛函编程,是一种编程范式,它将电脑运算视为数学上的函数计算,而且避免使用程序状态以及易变对象。

我的以为这个定义肥肠生动形象了。
函数式编程到处体现着数学的逻辑思想,经过减小外部依赖来避免外部变量的改变对于程式内部状态的改变,使得程序变得简易、声明式、易于维护。
这里推荐一下F大的《JS函数式编程指南》,系统介绍了函数式编程的思想。
中文版电子书下载地址走你:https://llh911001.gitbooks.io...
本文章是本身阅读后的一些理解和记录~html

First Class Funtcion

这个概念一样出于书中。规定了变量能够取的值得范围,以及该类型的值能够进行的操做。根据类型的值的可赋值情况,能够把类型分为三类。git

  1. 一级的(first class)。该等级类型的值能够传给子程序做为参数,能够从子程序里返回,能够赋给变量。大多数程序设计语言里,整型、字符类型等简单类型都是一级的。
  2. 二级的(second class)。该等级类型的值能够传给子程序做为参数,可是不能从子程序里返回,也不能赋给变量。
  3. 三级的(third class)。该等级类型的值连做为参数传递也不行。

在scala中,函数是能够做为参数来传递而且返回的,因此scala中的函数就是first class function
PS:scala 是一门多范式(multi-paradigm)的编程语言,设计初衷是要集成面向对象编程和函数式编程的各类特性。
所以,function做为变量的一种,能够被储存,看成参数传递,或者被复制给变量等等...程序员

Pure Function

首先弄清纯函数的概念:Pure function 意指相同的輸入,永遠會获得相同的輸出,并且沒有任何顯著的反作用。
它符合两个条件:编程

  1. 此函数在相同的输入值时,老是产生相同的输出。函数的输出和当前运行环境的上下文状态无关。
  2. 此函数运行过程不影响运行环境,也就是无反作用(如触发事件、发起http请求、打印/log等)。

简单来讲,也就是当一个函数的输出不受外部环境影响,同时也不影响外部环境时,该函数就是纯函数,也就是它只关注逻辑运算和数学运算,同一个输入总获得同一个输出。
好比slicesplice,可是slice是纯函数,而splice不是,由于后者会改变源数据。
这就是强调使用纯函数的缘由,由于纯函数相对于非纯函数来讲,在可缓存性、可移植性、可测试性以及并行计算方面都有着巨大的优点。数组

看一下书中的例子:缓存

// impure
var minimum = 21;

var checkAge = function(age) {
  return age >= minimum;
};

// pure
var checkAge = function(age) {
  var minimum = 21;
  return age >= minimum;
};

在impure 的版本中,checkAge 的結果將取決於 minimum 這個变量,换句话说,除了输入之外,它将取决于系统状态,一旦引用了外部环境,它就不符合pure了。
固然,也能够直接冻结变量,使得状态再也不变化,那么它也是一个纯函数:less

var immutableState = Object.freeze({
  minimum: 21,
});

Curry(柯里化)

书中定义柯里化的概念是:你能够只透過部分的參數呼叫一個 function,它會回傳一個 function 去處理剩下的參數。
函数柯里化是一种“预加载”函数的能力,经过传递一到两个参数调用函数,就能获得一个记住了这些参数的新函数。从某种意义上来说,这是一种对参数的缓存,是一种很是高效的编写函数的方法,将一个低阶函数转换为高阶函数的过程就叫柯里化。编程语言

//举个栗子
var checkage = min => (age => age > min);
var checkage18 = checkage(18);
checkage18(20);
// =>true
var curry = require('lodash').curry;

//柯里化两个纯函数
var match = curry((what, str) => str.match(what));
var filter = curry((f, ary) => ary.filter(f));

//判断字符串里有没有空格
var hasSpaces = match(/\s+/g);

hasSpaces("hello world");  // [ ' ' ]
hasSpaces("spaceless");  // null

var findSpaces = filter(hasSpaces);

findSpaces(["tori_spelling", "tori amos"]);  // ["tori amos"]

Compose—Functional饲养

假设要对某个字符串作一系列操做,咱们作的事情一多,嵌套的层数会很是深。相似于巢状堆积(好比c(b(a())))这种堆砌方式很是不直观,当咱们但愿代码以平行方式(书中成为左倾)组合执行时,就成为Compose
compose 的概念直接來自於數學課本,因此compose都有的一个特性:ide

// 結合律(associativity)
var associative = compose(f, compose(g, h)) == compose(compose(f, g), h);
// true

PointFree

pointfree 模式指的是,永远没必要说出你的数据。它的意思是说,函数无须说起将要操做的数据是什么样的函数式编程

// 非 pointfree,因為我們提到資料:word
var snakeCase = function(word) {
  return word.toLowerCase().replace(/\s+/ig, '_');
};

// pointfree
var snakeCase = compose(replace(/\s+/ig, '_'), toLowerCase);

这种风格可以帮助咱们减小没必要要的命名,让代码保持简洁和通用。
固然,为了在一些函数中写出Point Free的风格,在代码的其它地方必然是不那么Point Free的,这个地方须要本身取舍。

声明式与宣告式代码

// 命令式
var makes = [];
for (var i = 0; i < cars.length; i++) {
  makes.push(cars[i].make);
}
// 宣告式
var makes = cars.map(function(car) { return car.make; });

命令式代码:命令“机器”如何去作事情(how),这样无论你想要的是什么(what),它都会按照你的命令实现。
声明式代码:告诉“机器”你想要的是什么(what),让机器想出如何去作(how)。
命令式的循环要求你必须先实例化一个数组,并且执行完这个实例化语句以后,解释器才继续执行后面的代码。而后再直接迭代 cars 列表,手动增长计数器,就像你开了一辆零部件所有暴露在外的汽车同样。这不是优雅的程序员应该作的。

声明式的写法是一个表达式,如何进行计数器迭代,返回的数组如何收集,这些细节都隐藏了起来。它指明的是作什么,而不是怎么作。除了更加清晰和简洁以外,map 函数还能够进一步独立优化,甚至用解释器内置的速度极快的 map 函数,这么一来咱们主要的业务代码就无须改动了

相关文章
相关标签/搜索