函数可以将先前操作的结果记录在某个对象里,从而避免无谓的重复运算。这种优化方式被称为记忆(memoization)。JavaScript的对象和数组要实现这种优化是非常方便的。

比如说,我们想要一个递归函数来计算Fibonacci数列。一个Fib数字是之前两个Fib数字的和。最前面的两个数字是0和1。

var count=0;
var fib=function(n){
count++;
return n<2?n:fib(n-1)+fib(n-2);
};
for(var i=0;i<=10;i++){
console.log(fib(i))
} //
//
//
//
//
//
//
//
//
//
// count
//

这样是可以工作的,但它做了很多无谓的工作,fib函数被调用了453次。如果我们让该函数具备记忆功能,就可以显著地减少运算量。

我们在一个名为memo的数组里保存我们的存储结果,存储结果可以隐藏在闭包中。当函数被调用时,这个函数首先检查结果是否已经存在,如果已经存在,就立刻返回这个结果。

var count=0;
var fibonacci=function(){
var memo=[0,1];
var fib=function(n){
count++;
var result=memo[n];
if(typeof result!=='number'){
result=fib(n-1)+fib(n-2);
memo[n]=result;
}
return result;
};
return fib;
}(); for(var i=0;i<=10;i++){
console.log(fibonacci(i))
}
//结果同上 count
//

这个函数返回同样的结果,但它只被调用了29次。

我们可以把这种技术推而广之,编写一个函数来帮助我们构造带记忆功能的函数。memoizer函数取得一个初始的memo数组和formula函数。它返回一个管理memo存储和在需要时调用formula函数的recur函数。我们把这个recur函数和它的参数传递给formula函数:

var memoizer=function(memo,formula){
var recur=function(n){
var result=memo[n];
if(typeof result!=='number'){
result=formula(recur,n);
memo[n]=result;
}
return result;
};
return recur;
};

现在我们可以使用memoizer函数来定义fibonacci函数,提供其初始的memo数组和formula函数:

var fibonacci=memoizer([0,1],function(recur,n){
return recur(n-1)+recur(n-2);
});

通过设计这种产生另一个函数的函数,极大的减少了我们的工作量。例如,要产生一个可记忆的阶乘函数,我们只需提供基本的阶乘公式即可:

var factorial=memoizer([1,1],function(recur,n){
return n*recur(n-1);
});

js-语言精粹-函数记忆的更多相关文章

  1. 《JS语言精粹》学习笔记 函数部分の闭包

    要理解闭包,首先要理解变量作用域,变量的作用域就两种,全局变量和局部变量,函数内部可以直接读取全局变量,函数外部无法读取函数内部的局部变量. 闭包定义:能读取函数内部局部变量的函数就是闭包,而只有函数 ...

  2. 学习笔记——JS语言精粹

    JS作用域是基于词法作用域的顶级对象. JS是一门弱类型语言,强类型能在编译时检测错误. JS是唯一一门所有浏览器都能识别的语言. 块注释对于被注释的代码是不安全的,例如/*  var rm=/a*/ ...

  3. js语言精粹读书笔记一

    一.语法 1.

  4. js语言精粹

    1.typeof null == “object” ,所以不能通过typeof ~ == "object",判断为对象   : a.判断为null的,直接~ === null:b. ...

  5. JavaScript语言精粹 笔记02 函数

    函数函数对象函数字面量调用参数返回异常给类型增加方法递归作用域闭包回调模块级联套用记忆   函数 1 函数对象 在JS中函数就是对象.对象是“名/值”对的集合并拥有一个连接到原型对象的隐藏连接.对象字 ...

  6. 《JavaScript语言精粹》之函数化

    写在前面 看到好多书评和读书笔记都说<JavaScript语言精粹>字字珠玑,名不虚传..当然,要看得懂才行 其实个人认为函数化部分不是很好,举的例子不是十分恰当,之前看不懂是因为被成功误 ...

  7. 模板语言变量,js变量,js自执行函数之前嵌套调用

    1.模板语言变量 前端html页面中展示 {{ nodeIp }} 2.js变量引用模板语言变量 把模板语言变量传递给js,js去执行页面操作(变量的转换,只适用于字符串) var IP = &quo ...

  8. JavaScript中对象与函数的某些事[JavaScript语言精粹-N1]

    今天在读<JavaScript语言精粹>的时候,关于函数的一个部分,始终觉得有点难以理解,代码如下: 1: var obj = (function(){ 2: var value = 0; ...

  9. js课程 3-10 js中字符串函数数组函数和其它语言中对应函数的区别和联系是什么

    js课程 3-10  js中字符串函数数组函数和其它语言中对应函数的区别和联系是什么 一.总结 一句话总结:js中是对象点方法的形式,这些方法都是对象的方法,而在php.java中却不是这样. 1.j ...

随机推荐

  1. [原创]K8正方系统密码解密工具

    工具: K8_zfsoftDecode编译: 自己查壳组织: K8搞基大队[K8team]作者: K8拉登哥哥博客: http://qqhack8.blog.163.com发布: 2015/8/1 1 ...

  2. 【并发】2、AtomicReferenceFieldUpdater初体验

    对于volatile对象的原子更新 AtomicReferenceFieldUpdater这个对象进行原子更新的时候,外部操作对象只能是public,因为外部访问不到private对象,但是在内内部确 ...

  3. 在matlab中实现线性回归和logistic回归

    本文主要讲解在matlab中实现Linear Regression和Logistic Regression的代码,并不涉及公式推导.具体的计算公式和推导,相关的机器学习文章和视频一大堆,推荐看Andr ...

  4. Python中Gradient Boosting Machine(GBM)调参方法详解

    原文地址:Complete Guide to Parameter Tuning in Gradient Boosting (GBM) in Python by Aarshay Jain 原文翻译与校对 ...

  5. Linux后台进程管理以及ctrl+z(挂起)、ctrl+c(中断)、ctrl+\(退出)和ctrl+d(EOF)的区别(转)

    一.后台进程管理命令 fg.bg.jobs.&.ctrl + z.ctrl + c.ctrl + \.ctrl + d1. &加在一个命令的最后,可以把这个命令放到后台执行 ,如fir ...

  6. 面试基础知识集合(python、计算机网络、操作系统、数据结构、数据库等杂记)

    python python _.__.__xx__之间的差别 python中range.xrange和randrange的区别 python中 =.copy.deepcopy的差别 python 继承 ...

  7. 磁盘分区以及Linux目录挂载详解

    一.背景 一直以来,对于磁盘的分区以及Linux目录挂载的概念都不是很清晰,现在趁着春暖花开周末在家没事就研究了下它们,现在来分享我的理解. 二.概念详解 1.磁盘分区 磁盘分区是把物理的磁盘空间按照 ...

  8. Centos iptables防火墙关闭启动详解

    CentOS .0默认使用的是firewall作为防火墙,使用iptables必须重新设置一下 .直接关闭防火墙 systemctl stop firewalld.service #停止firewal ...

  9. es-09-spark集成

    es和spark的集成比较简单, 直接使用内部封装的一些方法即可 版本设置说明: https://www.elastic.co/guide/en/elasticsearch/hadoop/curren ...

  10. 【IT笔试面试题整理】二叉树中和为某一值的路径--所有可能路径

    [试题描述] You are given a binary tree in which each node contains a value. Design an algorithm to print ...