函数式编程二:js纯函数-模拟记忆函数memoize

在写记忆函数memoize前我们先来了解一下什么是纯函数?纯函数的好处是什么?为什么要使用纯函数?会有哪些副作用?
纯函数的概念
纯函数:相同的输入永远会得到相同的输出,而且没有任何可观察的副作用

  • 纯函数就类似数学中的函数(用来描述输入和输出之间的关系),y-f(x)。
  • lodash是一个纯函数的功能库,提供了对数组、数字、对象、字符串、函数等操作的一些方法 。
  • 数组中的slice和splice分别是:纯函数和不纯的函数
    slice返回数组中的指定部分,不会改变原数组。
    splice对数组进行操作返回该数组,会改变原数组
    在这里插入图片描述
    函数式编程不会保留计算中间的结果,所以变量是不可变的(无状态的)
    我们可以把函数的执行结果交给另一个函数去处理。

纯函数的好处
一、可缓存
了解了纯函数我们来说说纯函数的好处。
因为纯函数相同的输入始终都有相同的输出,所以我们可以把纯函数的结果缓存起来,那我们为什么要对结果进行缓存?比如说我们有一个函数,但这个函数执行起来特别的耗时,我们需要多次去调 用,那我们每次去调 用这个函数的时候,都需要等一段时间才能获取到这个结果,所以这对性能来说是有影响的。
我们可以在第一次执行的时候把这个结果缓存起来,当我们第二次再调用这个函数的时候我们不需要再等这么长的时间 ,而直接从缓存中来获取数据,从而提高性能,举个计算圆的面积的例子。

const _ = require("lodash");

function getArea(r) {
  //r半径
  console.log(r);
  return Math.PI * r * r;
}

let getAreaWithMemory=_.memoize(getArea);
console.log(getAreaWithMemory(4));
console.log(getAreaWithMemory(4));
console.log(getAreaWithMemory(4));

记忆函数。Lodash中提供了一个记忆函数memoize()函数,会接收一参数,该参数是一个纯函数,它内部会对纯函数进行处理,把这个纯函数的结果进行缓存,并且memozie函数还会返回一个带有记忆功能的函数。

运行结果
在这里插入图片描述
可以看出我们第一次调用这个方法 的时候打印出了圆的半径,并且把圆的面积输出来了,当我们第二次第三次再去调用的时候并且没打印出圆的半径,证明getArea只执行了一次,之后再执行的时候是直接从缓存里取的。
可好奇memoize方法里面是怎么运行的呢?那我们就来模拟一下这个方法的实现。

//模拟memoize方法的实现
function memoize(f){
  let cache={};
  return function(){
    let key=JSON.stringify(arguments);
    cache[key]=cache[key]||f.apply(f,arguments);
    return cache[key]
  }
}

let getAreaWithMemory=memoize(getArea);
console.log(getAreaWithMemory(4));
console.log(getAreaWithMemory(4));
console.log(getAreaWithMemory(4));

我们在memoize里定义了一个cache对象,对象中需要把我们的执行结果存储起来,第二次再去把存储的值获取到,因为函数f是一个纯函数,而纯函数有一个相同的特点始终根据相同的输入返回相同的输出,所以我们可以把函数的参数做为我们对象的键,把这个函数的执行结果做为对象的值
在这里插入图片描述
测试的结果和lodash中的memoize是一样的。
二、可测试
我们再来说第二个好处,就是可测试,因为我们纯函数始终有输入和输出,而单元测试其实在断言这个函数的结果,所以我们所有的纯函数都是可测试的函数,另外纯函数还方便并行处理
比如说我们在操作全局变量的时候就很可能发生一些意外的情况,多个线程同时修改同一个变量,那此时这个变量的结果是什么呢就不确定了。所以多线程的环境下操作共享内存的时候很可以出现意外的情况,而纯函数是一个封闭的空间,因为纯函数只依赖于参数,不需要访问共享的内存数据,所以在并行的环境下可以任意运行纯函数。

可能有小伙伴们说这好像对javascript没有关系,因为Js是单线程的,但是es6以后新增了一个Web Worker,可以开启新的线程

副作用
-没有可观察的副作用

//不纯的
let mini = 18;
function checkAge(age) {
  return age >= mini;
}
//纯的
function checkAge(age) {
  let mini = 18;
  return age >= mini;
}

例子中副作用让一个函数变的不纯,纯函数根据相同的输入返回相同的输出,如果函数依赖于外部的状态就无法保证输出相同,就会带来副作用。
副作用来源:

  • 配置文件
  • 数据库
  • 获取用户的输入

所有的外部交互都有可能带来副作用,副作用也使得方法通用性下降不适合扩展和可重用性,同时副作用会给程序中带来安全隐患给程序带来不确定性,但是副作用不可能完全禁止,尽可能控制它们在可控范围内发生。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值