资讯专栏INFORMATION COLUMN

函数式编程之记忆 js

DC_er / 3343人阅读

函数式编程之记忆
是一种时间换空间的方法,用牺牲空间的复杂度来换取时间的复杂度

字符串连接
function f() {
  var s = arguments.length + Array.prototype.join.call(arguments);
  console.log(s);
};

这里使用的是Array.prototype.join方法进行字符串连接
返回的是连接的结果

接下来,写一个具有记忆的函数
// 这是一个用于返回f()的带有记忆功能的函数
function memorize(f) {
  var cacho = {}; // 定义一个用于保存值的私有变量
  return function() {
    var key = arguments.length + Array.prototype.join.call(arguments, ",");
    if (key in cacho) 
      return cacho[key];
    else
      return cacho[key] = f.call(this, arguments);
  };
}

这是一个具有记忆的函数,用数组的长度和数组合并后组成的字符串作为属性名,进行保存,如果这个值存在则直接进行保存,如果值不存在则进行保存并返回(因为赋值语句会返回右值,所以return语句后无需再跟进行返回值的语句)

使用调试函数对其进行修改
// 这是一个用于返回f()的带有记忆功能的函数
function memorize(f) {
  var cacho = {}; // 定义一个用于保存值的私有变量
  console.log(cacho);
  return function() {
    var key = arguments.length + Array.prototype.join.call(arguments, ",");
    console.log(key);
    if (key in cacho) {
      console.log(cacho[key]);
      return cacho[key];
    }
    else {
      console.log(f.call(this,arguments));
      return cacho[key] = f.call(this, arguments);
    };
  };
}

这样就更加的明显了

使用这个函数

返回两个整数的最大公约数
欧几里得算法

由欧几里得最先发现,一个用于计算最大公因数的算法
function gcd(a, b) {
  var t;  // 用于保存中间变量
  if(a < b)  // 确保 a >= b
    t = a, a = b, b = t; 
  
  while(t != 0)
    t = a % b, a = b, b = t;
  return a;
}

利用欧几里得算法写的求两个数的最大公因数,运行一下

gcd(85, 187);
17

计算结果正确,使用刚刚实现的具有记忆功能的高阶函数,将函数传进去,生成了一个新的函数

var functiongcd = memorize(gcd);
Object {  }

使用这个函数
好吧。莫名进行死循环了。

Error: Script terminated by timeout at:
gcd@Scratchpad/1:35:9
memorize/<@Scratchpad/1:24:27
@debugger eval code:1:1

没办法继续排查错误

排查错误
// 这是一个用于返回f()的带有记忆功能的函数
function memorize(f) {
  var cache = {}; 
console.log(cache);
  return function() {
    var key = arguments.length + Array.prototype.join.call(arguments);
   console.log(key);
    if (key in cache) {
      console.log(cache[key]);
      return cache[key];
    }
    else {
      console.log(f.apply(this,arguments));
      return cache[key] = f.apply(this, arguments);
    };
  };
}

这个函数依旧写错了,call只能传入一个值,而apply能传入多个值

继续运行
gcdmemo(85, 187);
285,187 Scratchpad/1:17:4
17 Scratchpad/1:23:7
17

其中第一个Scratchpad/1:17:4返回指代的是

    if (key in cache) {
      console.log(cache[key]);
      return cache[key];
    }

其中第二个Scratchpad/1:23:7返回指代的是

      return cache[key] = f.apply(this, arguments);

好啦,非常明显,第一步是先将值缓存进入其私有变量,即保存进入闭包内部,然后第二个是发现这个值已经保存过了直接输出

(^o^)/,
js的记忆折腾完毕~

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

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

相关文章

  • 前端知识点整理

    摘要:难怪超过三分之一的开发人员工作需要一些知识。但是随着行业的饱和,初中级前端就业形势不容乐观。整个系列的文章大概有篇左右,从我是如何成为一个前端工程师,到各种前端框架的知识。 为什么 call 比 apply 快? 这是一个非常有意思的问题。 作者会在参数为3个(包含3)以内时,优先使用 call 方法进行事件的处理。而当参数过多(多余3个)时,才考虑使用 apply 方法。 这个的原因...

    Lowky 评论0 收藏0
  • 前端知识点整理

    摘要:难怪超过三分之一的开发人员工作需要一些知识。但是随着行业的饱和,初中级前端就业形势不容乐观。整个系列的文章大概有篇左右,从我是如何成为一个前端工程师,到各种前端框架的知识。 为什么 call 比 apply 快? 这是一个非常有意思的问题。 作者会在参数为3个(包含3)以内时,优先使用 call 方法进行事件的处理。而当参数过多(多余3个)时,才考虑使用 apply 方法。 这个的原因...

    snowLu 评论0 收藏0
  • 前端_JavaScript

    摘要:为此决定自研一个富文本编辑器。例如当要转化的对象有环存在时子节点属性赋值了父节点的引用,为了关于函数式编程的思考作者李英杰,美团金融前端团队成员。只有正确使用作用域,才能使用优秀的设计模式,帮助你规避副作用。 JavaScript 专题之惰性函数 JavaScript 专题系列第十五篇,讲解惰性函数 需求 我们现在需要写一个 foo 函数,这个函数返回首次调用时的 Date 对象,注意...

    Benedict Evans 评论0 收藏0
  • 如何理解JavaScript的原型和原型链?

    摘要:之前有朋友问怎么去理解原型和原型链的问题。理解原型链的小技巧将箭头视作泛化子类到父类关系那么图中所有的虚线将构成一个继承层级,而实线表示属性引用。原型链是实现继承的重要方式,原型链的形成是真正是靠而非。 之前有朋友问怎么去理解原型和原型链的问题。这个问题,在面试中,很多同学经常都会遇到。这里给大家讲讲,方便大家记忆。 JavaScript的特点JavaScript是一门直译式脚本...

    xuexiangjys 评论0 收藏0
  • 如何理解JavaScript的原型和原型链?

    摘要:之前有朋友问怎么去理解原型和原型链的问题。理解原型链的小技巧将箭头视作泛化子类到父类关系那么图中所有的虚线将构成一个继承层级,而实线表示属性引用。原型链是实现继承的重要方式,原型链的形成是真正是靠而非。 之前有朋友问怎么去理解原型和原型链的问题。这个问题,在面试中,很多同学经常都会遇到。这里给大家讲讲,方便大家记忆。 JavaScript的特点JavaScript是一门直译式脚本...

    adie 评论0 收藏0

发表评论

0条评论

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