纯函数

China☆狼群 提交于 2020-01-25 04:30:03

纯函数

什么是纯函数呢,我是在研究函数式编程时候发现的一个东西,想要知道什么是函数式编程,纯函数就是他学习的第一步。
那么就带着大家来分享一下什么是纯函数。

1-纯函数的概念

纯函数也是函数,只是相对普通的函数稍微特别了一点,概念如下:
纯函数是对相同输入返回相同输出的函数,不依赖(包含)任何外部变量,所以也不会产生改变外部环境变量的副作用。

1.1重点

通过上述概念分析得到他的重点主要集中在下面两条

1.函数的返回结果只依赖于它的参数

2.函数执行过程中没有副作用

1.2函数的返回结果只依赖于它的参数

首先第一条注意的地方。这里给大家上一段熟悉的代码,我们在js基础的课程中使用过一个求1-100的累加和,代码如下:

var start = 1;
var end = 2;
var sum = 0;
function fnsum(a,b){
    for(var i = a; i <= b; i++){
        sum += i
    }
    return sum
}
sum = fnsum(start,end)// 这里返回的值就是1-100之间的和。

这个代码看上去没什么问题,但是只能运行一次。当我们第一次运行的时候,使用到了一个全局变量sum来记录当前循环的总和,确实能够正常输出结果,但是当我们第二次运行的时候,这个sum并不是初始值0,而是5500。这个时候第二次运行的结果就被sum这个全局变量影响到了。
这就不是一个纯函数。想要拿到纯函数稍微改造一下:

var start = 1;
var end = 2;

function fnsum(a,b){
    var sum = 0;
    for(var i = a; i <= b; i++){
        sum += i
    }
    return sum
}
var sum = fnsum(start,end)// 这里返回的值就是1-100之间的和。

现在再来看这个代码,跟外面的全局变量已经完全没有关系了。他既没有引用外面的全局变量也没有改变外面的全局变量。
所以纯函数又像家里的计算器,每次计算的内容,只跟你输入的数字和符号有关系,绝对不能被其他变量影响,这才是纯函数

1.3函数执行过程中没有副作用

接着我们再来看几个常见的方法
比如 concat、slice、join、toString 那么这几个方法,大家先想一下他们有什么共同的特点吗?

他们共同的特点就是都不会影响原数组的,都会返回一个新的数组供大家使用。如果大家对这个原数组和新数组没什么使用上的概念。咱们来对比一下slice和splice的区别,两者都是数组截取的方法,但是slice一个会改变原数组一个不改变原数组

    splice截取方式
    var arr = [1,2,3];
    var newarr = arr.splice(1);
    console.log(newarr)//[2,3]
    console.log(arr)//[1,2,3]

    slice截取方式
    var arr = [1,2,3];
    var newarr = arr.slice(1);
    console.log(newarr)//[2,3]
    console.log(arr)//[1]

这splice改变了原数组,如果后续代码需要继续对arr数组进行操作的话,那么就会对后面的程序造成很大的影响,造成存在隐性的bug问题。
所以es6后面的语法规范都倾向于不修改原数组。

结合上述两点,没有引用和改变全局变量,也没有明显副作用的函数称之为纯函数

2-纯函数的优势

那么我们来总结一下纯函数的优势

2.1可缓存性

调用传入相同的代码的时候,纯函数会优先取缓存

function sum(a){
    return a*a;
}

sum(2);
//=> 4

sum(2); // 从缓存中读取输入值为 2 的结果
//=> 4

sum(4);
//=> 16

sum(4); // 从缓存中读取输入值为 4 的结果
//=> 16

2.2可移植性

一个纯函数,是完全自给自足的,它需要的所有东西都能轻易获得。可移至性说的就是耦合度的问题了,可以随意搬到另一个项目或者组件中去使用,因为他没有改变和引入任何的全局变量,他只跟你传入的参数有关系,而且返回的是一个新的值。这种思维就类似于vue组件化,把一个个的页面拆分开来,就像堆积木,可以随意拼接

// 不纯的
var signUp = function(attrs) {
  var user = saveUser(attrs);
  welcomeUser(user);
};

var saveUser = function(attrs) {
    var user = Db.save(attrs);
    ...
};

var welcomeUser = function(user) {
    Email(user, ...);
    ...
};
// 上述代码在调用的时候,saveUser方法固定去使用了Db数据库,如果出现移植,没有Db数据库,导致项目就跑不起来。
// 下面的代码在调用的时候,把数据库也当作参数传入函数,这整个纯函数就可以随意移植,完全自给自足,没有任何耦合性问题。

// 纯的
var signUp = function(Db, Email, attrs) {
  return function() {
    var user = saveUser(Db, attrs);
    welcomeUser(Email, user);
  };
};

var saveUser = function(Db, attrs) {
    ...
};

var welcomeUser = function(Email, user) {
    ...
};


2.3 可测试性

我们平常工作中,项目的代码会越来越多,基础功底稍有不慎,模块之间或者组件之间的耦合性越来越差,一旦代码量达到一定程度,将不可避免的包含某种未知bug,甚至当清除了这个bug的时候,又会产生新的未知bug。在JavaScript中可以很容易地创建全局变量,这些变量在很多的函数中都能访问修改,这也是导致发生bug的常见原因。并且难以调试。

那么用纯函数的方式更容易测试,不需要结合上下文,不用担心全局变量的影响,更容易实现所谓的单元测试。

3-总结

说了那么多,那么现在我们知道为什么要使用纯函数了吗,因为纯函数,更加可靠,不会存在一些意料之外的问题,也不会对外面的全局变量和其他函数扯上关系,也就是说不会对外界造成任何影响,无论哪个项目需要可以非常简单的去移植过去,并且后期调试和改bug的时候,定位更加清晰。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!