深刻理解javascript系列(十四):纯函数

虽然我是计算机方向毕业的学生,可是认识到纯函数,仍是在学react的时候...javascript

相同的输入总会获得相同的输出,而且不会产生反作用的函数,就是纯函数。前端

咱们能够经过一个是否会改变原始数据的两个一样的功能的方法来区别纯函数与非纯函数之间的不一样。java

但愿有能有这么一个函数,可以获取到引入数组的最后一项。那么能够经过如下两种方式来实现。react

function getLast(arr) {
    return arr[arr.length];
}

function getLast_(arr) {
    return arr.pop();
}

var source = [1,2,3,4];

var last = getLast(source);    //返回结果4,原数组不变
var last_ = getLast_(source);    //返回结果4,原数组发生改变复制代码

getLast与getLast_虽然都可以得到数组的最后一项值,可是getLast_改变了原数组。而当原数组被改变,咱们再次调用该方法时,获得的结果就会变得不同。这种不可预测的封装方式是很是糟糕的,它会把咱们的数据搞的很是混乱。在JavaScript原生支持的数据方法中,也有许多不纯的方法,咱们在使用时要多加警戒,要清晰地知道原始数据的改变是否会留下隐患。数组

var source = [1,2,3,4,5];

source.slice(1, 3);        //纯函数返回[2,3],source不变
source.splice(1, 3);       //非纯函数返回[2,3,4],source被改变

source.pop();        //非纯函数
source.push(6);      //非纯函数
source.shift();      //非纯函数
source.unshift();    //非纯函数
source.reverse();    //非纯函数复制代码

与这种会改变原始数据的函数相比,纯函数明显更加可靠。很显然咱们都不但愿本身的数据在通过几回调用后就变得一团糟。缓存

纯函数还有一个重要的特色,那就是除了传入的参数外,不依赖任何外界的信息与状态。以下面这个例子。bash

var name = 'pan';

function sayHello() {
    return 'Hello, ' + name;
}
sayHello();    //Hello, pan

//当咱们有其它需求时须要改变name的值
name = 'zhang';
sayHello();    //Hello, zhang复制代码

一样的调用,可是因为sayHello函数依赖于外界的name变量,所以当外界变量发生变化时,函数的运行结果就变得不同。很显然这并非咱们封装函数时所但愿看到的情况,由于这样的变化是不可预测的。所以,对于上面的例子,咱们应该把name看成一个参数传入,这样就可以直观地看到该函数执行时会输出的结果了。微信

function sayHello(name) {
    return 'Hello, ' + name;
}复制代码

1.  纯函数的可移植性

在封装一个函数、一个库或一个组件时,其实都指望一次封装,多处使用,而纯函数恰好具有这样的特性。闭包

纯函数不依赖参数以外的值,所以纯函数的依赖很是明确。也正是如此,咱们才可以把一些经常使用的功能封装成一个公共方法,这样之后遇到相似的场景时就不用再从新封装了。app

咱们知道一个页面的URL里经常会在‘?’后面带有参数,例如https://www.baidu.com/s?word=javascript&tn=02003390_7_hao_pg。不少时候咱们须要从这段URL中,获取某些参数对应的值。例如,这个例子中的‘word’的值为javascript。那么想要封装这样一个纯函数,应该怎么作了?

function getParams(url, param) {
    if(!/\?/.test(url)) {
        return null;
    }

    var search = url.split('?')[1];
    var array = search.split('&');

    for(var i = 0; i<array.length; i++) {
        var tmp = array[i].split('=');
        if(tmp[0] === param) {
            return decodeURIComponent(tmp[1]);
        }
    }
    
    return null;
}
var url= 'https://www.baidu.com/s?word=javascript&tn=02003390_7_hao_pg';
getParams(url, 'word');    //javascript复制代码

虽然getParams并不是彻底健壮,可是已经足以体现纯函数可移植的特色。咱们能够在任何须要从url中取得参数对应值的地方调用该方法。

2.  纯函数的可缓存性

在实践中咱们可能会处理大量的数据,例如根据日期,获得当日相关的数据,并处理成前端可以使用的数据。假设咱们封装了一个process方法来处理天天的数据,而这个处理过程会很复杂。若是不缓存处理结果,那么每次想要获得当天的数据时,就不得不从原始数据在转换一次。当数据的处理足够复杂时,那么极可能不是性能最优的解决方案。而纯函数的特色是,相同的输入总能获得相同的输出,所以若是将处理过每一台年的数据缓存起来,那么第二次或者更屡次的想要获得的当天的数据时,就不用经历复杂的处理过程了。

//传入日期,获取当天的数据
function process(date) {
    var result = '';
    //略掉中间复杂的处理过程

    return result;
}

function withProcess(base) {
    var cache = {};
    return function() {
        var date = arguments[0];
        if(cache[date]) {
            return cache[date];
        }
        return base.apply(base, arguments);
    }
}

var _process = withProcess(process);

//通过上面一句代码处理以后,就可使用_process来获取咱们想要的数据了。
//若是数据存在,就返回缓存中的数据,若是不存在,则就调用process方法从新获取。复制代码

 上面利用了闭包的特性,将处理过的数据都缓存在了cache中。这种方式算是高阶函数的运用了。

什么是纯函数,纯函数有什么特色,以及为何要尽可能使用纯函数想必这个记录也算完整了。

虽然在实践中并非全部的场景都可以使用纯函数,但仍是应尽可能在合适的场景使用它。

感谢阳波大神。

这些都是我以往的学习笔记。若是您看到此笔记,但愿您能指出个人错误。有这么一个群,里面的小伙伴互相监督,坚持天天输出本身的学习心得,不输出就出局。但愿您能加入,咱们一块儿终身学习。欢迎添加个人我的微信号:Pan1005919589

相关文章
相关标签/搜索