什么是Memoization函数?
Memoization(记忆化)是一种优化技术,它可以缓存函数的结果,达到减少重复计算的目的。当使用相同的参数调用同一个函数时,它会从缓存中返回结果而不是重新计算。这种技术在计算量大、重复计算较多的函数中非常实用。
下面我们就来看看如何用JavaScript编写一个简单的Memoization函数。
实现Memoization函数的两种方法
方法一:闭包(Closure)
下面的函数代码就是用闭包实现Memoization函数的例子:
function memoize(func) {
var cache = {};
return function() {
var key = JSON.stringify(arguments);
if (cache[key]) {
console.log("从缓存中取得计算结果:");
console.log(cache[key]);
return cache[key];
} else {
console.log("进行计算并缓存结果:");
var val = func.apply(this, arguments);
cache[key] = val;
return val;
}
};
}
这段代码中,memoize函数返回了一个闭包函数,这个闭包函数引用了外部的cache变量。当调用返回的闭包函数时,先进行参数的序列化(将多个参数转换为一个字符串),然后检查缓存中是否存在这个参数的计算结果。如果存在,则直接返回缓存中的值;否则进行函数计算,并将结果存入缓存,然后才返回结果。
这种方法只适用于原始类型或序列化后的参数,不适合传递引用类型的参数。
方法二:Map
使用ES6的Map数据结构也可以实现Memoization函数。下面的代码就是用Map实现Memoization函数的例子:
function memoize(func) {
var cache = new Map();
return function() {
var key = JSON.stringify(arguments);
if (cache.has(key)) {
console.log("从缓存中取得计算结果:");
console.log(cache.get(key));
return cache.get(key);
} else {
console.log("进行计算并缓存结果:");
var val = func.apply(this, arguments);
cache.set(key, val);
return val;
}
};
}
这段代码中,memoize函数同样返回了一个闭包函数,这个闭包函数引用了外部的cache变量。当调用返回的闭包函数时,先进行参数的序列化(将多个参数转换为一个字符串),然后检查缓存中是否存在这个参数的计算结果。如果存在,则直接返回缓存中的值;否则进行函数计算,并将结果存入缓存,然后才返回结果。
这种方法适用于所有类型的参数,因为Map可以存储引用类型。
使用Memoization函数的例子
下面是使用Memoization函数的一个例子:
function fibonacci(n) {
if (n === 0) return 0;
if (n === 1) return 1;
return fibonacci(n - 1) + fibonacci(n - 2);
}
var memoizedFibonacci = memoize(fibonacci);
console.log(memoizedFibonacci(10));
console.log(memoizedFibonacci(10));
这段代码中,我们定义了一个递归函数fibonacci(n),它能够计算斐波那契数列的第n项。然后我们使用memoize函数创建一个新的函数,这个函数在调用fibonacci(n)时会缓存计算结果。最后我们分别调用memoizedFibonacci(10)两次,发现第二次调用时不再进行计算,而是直接从缓存中返回结果:
进行计算并缓存结果:
55
从缓存中取得计算结果:
55
结论
Memoization是一种非常实用的优化技术,它可以降低函数计算的成本,提高程序的运行效率。我们可以使用闭包或Map来实现Memoization函数,然后在需要进行重复计算的函数中使用这个函数。当然,Memoization函数并不是万能的,它也有一些局限性,需要我们在使用时加以注意。