资讯专栏INFORMATION COLUMN

JS 利用高阶函数实现函数缓存(备忘模式)

hightopo / 1464人阅读

摘要:所以这里可以利用高阶函数的思想来实现一个简单的缓存,我可以在函数内部用一个对象存储输入的参数,如果下次再输入相同的参数,那就比较一下对象的属性,把值从这个对象里面取出来。

1. 高阶函数

高阶函数就是那种输入参数里面有一个或者多个函数,输出也是函数的函数,这个在js里面主要是利用闭包实现的,最简单的就是经常看到的在一个函数内部输出另一个函数,比如

var test = function() {
    return function() {}
}

这个主要是利用闭包来保持着作用域:

var add = function() {
    var num = 0;
    return function(a) {
        return num = num + a;
    }
}
add()(1);      // 1
add()(2);      // 2

这里的两个add()(1)和add()(2)不会互相影响,可以理解为每次运行add函数后返回的都是不同的匿名函数,就是每次add运行后return的function其实都是不同的,所以运行结果也是不会影响的。

如果换一种写法,比如:

var add = function() {
    var num = 0;
    return function(a) {
        return num = num + a;
    }
}
var adder = add();
adder(1); // 1
adder(2); // 3

这样的话就会在之前运算结果基础上继续运算,意思就是这两个 adder 运行的时候都是调用的同一个 num

2. 高阶函数实现缓存(备忘模式)

比如有个函数:

var add = function(a) {
    return a + 1;
}

每次运行add(1)的时候都会输出2,但是输入1每次还是会计算一下1+1,如果是开销很大的操作的话就比较消耗性能了,这里其实可以对这个计算进行一次缓存。
所以这里可以利用高阶函数的思想来实现一个简单的缓存,我可以在函数内部用一个对象存储输入的参数,如果下次再输入相同的参数,那就比较一下对象的属性,把值从这个对象里面取出来。

const memorize = function(fn) {
  const cache = {}
  return function(...args) {
    const _args = JSON.stringify(args)
    return cache[_args] || (cache[_args] = fn.apply(fn, args))
  }
}
const add = function(a) {
  return a + 1
}
const adder = memorize(add)
adder(1)    // 2    cache: { "[1]": 2 }
adder(1)    // 2    cache: { "[1]": 2 }
adder(2)    // 3    cache: { "[1]": 2, "[2]": 3 }

JSON.stringify把传给 adder 函数的参数变成了字符串,并且把它当做 cache 的 key,将 add 函数运行的结果当做 value 传到了 cache 里面,这样 memorize 的匿名函数运行的时候会返回cache[_args],如果cache[_args]不存在的话就返回fn.apply(fn,args),把fn.apply(fn, arguments)赋值给cache[_args]并返回。
注意:cache不可以是Map,因为Map的键是使用===比较的,[1]!==[1],因此即使传入相同的对象或者数组,那么还是被存为不同的键。

const memorize = function(fn) {        //  X 错误示范
  const cache = new Map()
  return function(...args) {
    return cache.get(args) || cache.set(args, fn.apply(fn, args)).get(args)
  }
}
const add = function(a) {
  return a + 1
}
const adder = memorize(add)
adder(1)    // 2    cache: { [ 1 ] => 2 }
adder(1)    // 2    cache: { [ 1 ] => 2, [ 1 ] => 2 }
adder(2)    // 3    cache: { [ 1 ] => 2, [ 1 ] => 2, [ 2 ] => 3 }

本文是系列文章,可以相互参考印证,共同进步~

JS 抽象工厂模式

JS 工厂模式

JS 建造者模式

JS 原型模式

JS 单例模式

JS 回调模式

JS 外观模式

JS 适配器模式

JS 利用高阶函数实现函数缓存(备忘模式)

JS 状态模式

JS 桥接模式

JS 观察者模式

网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出~

参考: P78

PS:欢迎大家关注我的公众号【前端下午茶】,一起加油吧~

另外可以加入「前端下午茶交流群」微信群,长按识别下面二维码即可加我好友,备注加群,我拉你入群~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/92269.html

相关文章

  • JS 原型模式

    摘要:你可以使用像下面这样的代码为上面的例子来实现车辆模具是福特总结原型模式在里的使用简直是无处不在,其它很多模式有很多也是基于的,这里大家要注意的依然是浅拷贝和深拷贝的问题,免得出现引用问题。 1. 简介 原型模式(Prototype pattern),用原型实例指向创建对象的类,使用于创建新的对象的类的共享原型的属性与方法。 2. 实现 对于原型模式,我们可以利用JavaScript特有...

    Coding01 评论0 收藏0
  • JS 桥接模式

    摘要:简介桥接模式将抽象部分与它的实现部分分离,使它们都可以独立地变化。同时桥接模式也有自己的缺点大量的类将导致开发成本的增加,同时在性能方面可能也会有所减少。 1. 简介 桥接模式(Bridge)将抽象部分与它的实现部分分离,使它们都可以独立地变化。其实就是函数的封装,比如要对某个DOM元素添加color和backgroundColor,可以封装个changeColor函数,这样可以在多个...

    chemzqm 评论0 收藏0
  • JS 回调模式

    摘要:对这种问题的解决方法是采用回调模式。可以将节点隐藏逻辑以回调函数的方式传递给并委托执行检查参数是否为可调用复杂逻辑,筛选出符合的元素那么现在回调函数可选,重构后加入回调函数参数的仍然可以像以前一样使用,而不会破坏旧的原始代码。 1. 回调示例 如果有个模块 findeNodes() ,任务是找到期望的 DOM 元素并使用 hide() 处理: function findNodes() ...

    oliverhuang 评论0 收藏0
  • JS 单例模式

    摘要:但是如何在对构造函数使用操作符创建多个对象的时候仅获取一个单例对象呢。单例的实例引用单例构造函数单例私有属性和方法暴露出来的对象改进之前在构造函数中重写自身会丢失所有在初始定义和重定义之间添加到其中的属性。 1. 单例模式 单例模式 (Singleton) 的实现在于保证一个特定类只有一个实例,第二次使用同一个类创建新对象的时候,应该得到与第一次创建对象完全相同的对象。当创建一个新对象...

    姘存按 评论0 收藏0
  • JS 状态模式

    摘要:简介状态模式允许一个对象在其内部状态改变的时候改变它的行为,对象看起来似乎修改了它的类。状态通常为一个或多个枚举常量的表示。简而言之,当遇到很多同级或者的时候,可以使用状态模式来进行简化。 1. 简介 状态模式(State)允许一个对象在其内部状态改变的时候改变它的行为,对象看起来似乎修改了它的类。其实就是用一个对象或者数组记录一组状态,每个状态对应一个实现,实现的时候根据状态挨个去运...

    xingqiba 评论0 收藏0

发表评论

0条评论

hightopo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<