JavaScript函数式编程

javascript是一门多范式(multi-paradigm)的编程语言,它即支持命令式(imperative)/面向过程(procedural)编程,也支持面向对象编程(oop object-Oriented Programming),还支持函数式编程(functional programming).
常见的三种编程范式

1 命令式 c
2 函数式 lisp
3 面向对象 java c++

什么是函数式编程

我们先来看下命令式是怎么求一个数组的最大值的
var arr = [1,2,3,4,5,6];
var len = arr.length;
var max = arr[0];
for(var i=0;i<len;i++){
if(arr[i] > max){

max = arr[i];

}
}
这就是命令式编程 for循环的形式 7行代码,多了几个全局变量

我们尝试改造下,采用排序的方式

var max = arr.sort((a, b) => b - a)[0];

确实简洁不少。但有一个负作用,把arr的内容给修改了。这不是一个纯函数该干的事。我们再优化下

var sum = arr.reduce(function (a, b) {
return a > b?a:b
});
再变成箭头函数
var sum = arr.reduce((a,b) =>{return a>b?a:b;});
没有多余的全局变量,也没有修改调动的数组。这就是一个函数式编程的一个典型例子。

近年来。函数式编程越来越多得到开发这的青睐,函数式编程是一种强调减少对程序外部状态产生改变的方式。因此它鼓励使用不可变数据结构合纯函数编程,鼓励使用声明式编程而非命令式编程,通过简而已懂的函数命令方式,描述目标性质,得到想要的结果,而非流程式,指令式。函数式编程即不依赖外部状态,也不修改外部状态,可以使代码更容易理解,维护,测试,不易出错。

函数式编程有5大特性

  • 纯函数
  • 不可变数据
  • 无副作用
  • 函数组合
  • 函数柯里化

纯函数

纯函数是一种函数,它不改变程序的外部状态,也不会造成数据可变性,纯函数的输出完全依赖于它的输入值,对于相同的输入,永远返回相同的输出。

比如 slice 和 splice,这两个函数的作用并无二致——但是注意,它们各自的方式却大不同,但不管怎么说作用还是一样的。我们说 slice 符合纯函数的定义是因为对相同的输入它保证能返回相同的输出。而 splice 却会嚼烂调用它的那个数组,然后再吐出来;这就会产生可观察到的副作用,即这个数组永久地改变了。

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);
//=> []

纯函数的好处非常的多。这让单元测试,可缓存性,可移植行,文档化,成为很轻松的事。

不可变数据

不可变数据指一个值,一旦被创建,就永远不会发生改变。在js基本数据类型中,数字,字符串和布尔值是永远不变的。但对象和数组的数据结构在某些操作下是可变的。

var x = [1,2]
console.log(x)
x.push(3);
console.log(x)  
//数组可变,x被改变了

var x = [1,2],y;
console.log(x);
y = x.concat([3]);
console.log(x)
//数组不可变

无副作用

函数副作用是指当调用函数是,除了返回函数值之外,还对该函数外部的状态产生了改变。函数副作用会给程序带来不必要的麻烦,给程序带来潜在的错误,并且降低程序的可读性。

var x = 1
var fn = function(y){
   x = x+y
}
fn(2)
console.log(x)

函数组合

函数组合就是组合两到多个函数来生成一个新函数的过程。将函数组合在一起,就像将一连串管道扣合在一起,让数据流过一样。

简而言之,函数 f 和 g 的组合可以被定义为 f(g(x)),从内到外(从右到左)求值。也就是说,求值顺序是:

例如underscore里面compose函数的实现

function compose() {
    var args = arguments;
    var start = args.length - 1;
    return function() {
        var i = start;
        var result = args[start].apply(this, arguments);
        while (i--) result = args[i].call(this, result);
        return result;
    };
};

compose(d, c, b, a)

函数柯里化

函数柯里化指把接受多个参数的多参函数转换成每次只接受一个参数的单参函数,并且返回可以接受余下参数的新函数,最大的特点是延迟执行,增加了函数的适用性。

上述几个点都可以分开单独的来阐述,网上也有特别多的介绍。后续再一一展开来描述下上面的特性

正在努力的改变自己的编码习惯朝着函数式编程努力着

相关推荐