javascript高级知识点——memoization

memoization是一种非常有用的优化技术,它缓存特定输入产生的相应结果。这样麻烦的查找和迭代计算可以尽可能的减少。

它基本的思想是针对特定的输入,已经计算过的结果都是通过缓存当中的数据直接返回而不是经过重复的计算。

实现记忆函数

我们可以简单的将memoization理解为记忆函数经过特定输入产生的结果。

下面是一种基本简单且实用的实现方法,可以很清晰的显示记忆函数的结构

function memoize( fn ) {
    return function () {
        // 将参数转为数组
        var args = Array.prototype.slice.call(arguments);
        // 创建缓存对象在目标函数对象里
        fn.cache = fn.cache || {};
        // 如果缓存当中有相应的结果直接从缓存中返回,否则重新计算并存储缓存对象
        return args in fn.cache ? fn.cache[args] : fn.cache[args] = fn.apply(this, args);
    };
}

为了方便我们可以更形象的理解记忆函数,我们将上面的三目运算符改成if语句,并添加log。

function memoize( fn ) {
    return function () {
        // 将参数转为数组
        var args = Array.prototype.slice.call(arguments);
        // 创建缓存对象在目标函数对象里
        fn.cache = fn.cache || {};
        // 如果缓存当中有相应的结果直接从缓存中返回,否则重新计算并存储缓存对象
        var results;
        if (args in fn.cache) {
            console.log(‘返回结果来自于缓存:‘);
            results = fn.cache[args];
        }else {
            console.log(‘返回结果来自于函数计算:‘);
            results = fn.cache[args] = fn.apply(this, args);
        }
        return results
    };
}

实际使用

这里我们将其运用到实际中去,下面是一个计算最大公约数的函数。但它不是学习的要点,我们只要知道它接收两个数字,并返回他们的最大公约数。

// 这是一个计算最大公约数的函数
function gcd(a ,b){
    var t;
    if (a < b) t = b, b = a, a = t;
    while(b != 0) t=b, b= a%b, a=t;
    return a;
}

var cachedGcd = memoize(gcd);

console.log(cachedGcd(85, 187)); // 返回结果来自于函数计算: 17

console.log(cachedGcd(85, 187)); // 返回结果来自于缓存: 

在上面这段代码,可以看到经memoize处理过的gcd函数便具备记忆缓存的作用。不只是gcd,对于任何特定输入产生特定结果的函数都可以使用记忆函数。

简单测试

使用time简单的测试一下非记忆时,和记忆时函数调用的时间。在不同的浏览器有不同的结果,但是,整体来看记忆时的时间是比非记忆时要短的。

console.time(‘non-memoized‘)
cachedGcd(85,187);
console.timeEnd(‘non-memoized‘)
console.time(‘memoized‘)
cachedGcd(85,187);
console.timeEnd(‘memoized‘)

由于gcd函数涉及的运算相对比较少,这还不能很明显的体现记忆函数的优势,试想一下,如果一个函数运算量很大很大。那么通过缓存返回的结果将直接跳过这些复杂的运算,迅速返回结果。

时间: 2024-11-05 23:47:33

javascript高级知识点——memoization的相关文章

javascript高级知识点——指定上下文实现

代码信息来自于http://ejohn.org/apps/learn/. 当我们将一个对象的点击事件绑定到一个事件触发元素时会发生什么? <ul id="results"> </ul> <script> var Button = { click: function(){ this.clicked = true; } }; var elem = document.createElement("li"); elem.innerHTML

javascript高级知识点——内置对象原型

代码信息来自于http://ejohn.org/apps/learn/. 可以修改内置对象的方法. if (!Array.prototype.forEach) { Array.prototype.forEach = function(fn){ for ( var i = 0; i < this.length; i++ ) { fn( this[i], i, this ); } }; } ["a", "b", "c"].forEach(fun

javascript高级知识点——函数的长度

代码信息来自于http://ejohn.org/apps/learn/. 函数的长度属性如何工作? function makeNinja(name){} function makeSamurai(name, rank){} console.log( makeNinja.length == 1, "只定义了一个形参" ); console.log( makeSamurai.length == 2, "定义了两个形参" ); 很清楚,函数的长度就是定义形参的个数. 我们

javascript高级知识点——继承

代码信息来自于http://ejohn.org/apps/learn/. 继承是如何工作的 function Person(){} function Ninja(){} Ninja.prototype = new Person(); var ninja = new Ninja(); console.log( ninja instanceof Ninja, "ninja自动接收Ninja.prototype里的属性" ); console.log( ninja instanceof Pe

javascript高级知识点——函数原型

代码信息来自于http://ejohn.org/apps/learn/. 向函数的原型中添加方法 function Ninja(){} Ninja.prototype.swingSword = function(){ return true; }; var ninjaB = new Ninja(); console.log( ninjaB.swingSword(), "Method exists and is callable." ); 通过实例化对象可以访问,因为构造函数实例化的对象

javascript高级知识点——实例类型

代码信息来自于http://ejohn.org/apps/learn/. 分析一下对象的结构 function Ninja(){} var ninja = new Ninja(); console.log( typeof ninja == "object", "仍然是对象" ); console.log( ninja instanceof Ninja, "是Ninja的实例" ); console.log( ninja.constructor =

javascript高级知识点——临时作用域

代码信息来自于http://ejohn.org/apps/learn/. 自执行,临时,函数 (function(){ var count = 0; })(); 这是一个简单的自执行匿名函数. 做一个点击计数 document.addEventListener("click", (function(){ var numClicks = 0; return function(){ alert( ++numClicks ); }; })(), false); 关键代码是,自执行匿名函数,返

《javascript高级程序设计》第八章知识点

1.window对象: 由于window对象同时扮演着ECMAScript中Global对象的角色,因此全局作用域中的变量,函数都会成为window对象的属性和方法. 如果页面中包含框架,则每个框架都有自己的window对象,保存在frames集合中可以通过数值索引,从0开始,从左至右,由上至下. 系统对话框: alert()         显示带有一段消息和一个确认按钮的警告框 confirm()    显示带有一段消息以及确认按钮和取消按钮的对话框. prompt()    显示可提示用户

《javascript高级程序设计》第五章知识点总结

第五章知识点总结 1.object类型 访问对象的方法:①点表示法        (people.name) :      ②方括号表示法         (people[name]). 常用方法:hasOwnProperty()         用于检查给定属性在当前对象实例中是否存在 isPrototypeOf()              用于检测传入的对象是否传入对象原型 toString()                        返回对象的字符串表示 valueOf()