_.memoize
这个函数的功能
创建一个会缓存 func 结果的函数。 如果提供了 resolver ,就用 resolver 的返回值作为 key 缓存函数的结果。 默认情况下用第一个参数作为缓存的 key。 func 在调用时 this 会绑定在缓存函数上。
注意: 缓存会暴露在缓存函数的 cache 上。 它是可以定制的,只要替换了 _.memoize.Cache 构造函数,或实现了[Map]的 delete, get, has, 和 set方法。
源码
function memoize(func, resolver) {
if (typeof func !== 'function' || (resolver != null && typeof resolver !== 'function')) {
throw new TypeError('Expected a function')
}
const memoized = function(...args) {
const key = resolver ? resolver.apply(this, args) : args[0]
const cache = memoized.cache
if (cache.has(key)) {
return cache.get(key)
}
const result = func.apply(this, args)
memoized.cache = cache.set(key, result) || cache
return result
}
memoized.cache = new (memoize.Cache || Map)
return memoized
}
memoize.Cache = Map
export default memoize
解析
这个函数主要的功能就是缓存函数所得到的结果,如果你的参数没有改变时候,这时候就不用重复计算,直接返回值
就像你第一次计算15x15时候,你会去花15s计算,这就是没有缓存的时候函数的计算运行时间。
后来你将这个结果记在了你手边的笔记本上面,再遇到这个题的时候,你发现还是15x15,那么你就去找笔记本,花费了2s,发现了结果225,那么相对于你自己计算,你就快了13s。
这就是日常生活中我们最常见的缓存。这个函数的作用也是这个原理,理解了这个为什么需要缓存的原因,我们看源码就会轻松很多。
函数的前三行,其实就是传入的参数的一个合法的检验,如果func不是函数形式就会直接抛出错误,resolver这个函数的返回值会作为这个缓存函数的标识符。
举个例子
像上面的15x15=225这样,你去寻找的时候,是不是要找到第一个被乘数15,然后再找乘数15,最后看答案225,如果你寻找的时候,觉得麻烦,就像看一下被乘数就直接找结果,此时,又有一个15x16 在你的笔记本上面,你这次找错了,你就没办法得到正确的数了。这种情况就像是没有resolver的时候。
而又resolver的时候呢,就相当于你在15x15=225旁边标记了一个😊,你下次寻找的时候不会再去寻找15了,你直接去寻找这个😊。
但此时又有另一个问题,如果你的重复用到了这个😊,那么就会得到错误的缓存,所以大家在用这个resolver时候一定要保证他返回的唯一性。
代码解析
这个memoized函数其实就是一个高阶函数,利用闭包,将函数整体返回回来。
const memoized = function (...args) {
const key = resolver ? resolver.apply(this, args) : args[0];
const cache = memoized.cache;
if (cache.has(key)) {
return cache.get(key);
}
const result = func.apply(this, args);
memoized.cache = cache.set(key, result) || cache;
return result;
};
这一部分就是返回来的函数,我们可以看到,它的key值是通过检查resolver是否存在,如果存在就调用它,并把它的返回值作为key值,否则就把参数的第一项作为key值。
然后他会检查这个值在缓存里面是否存在,如果存在直接返回,如果不存在再进行计算,并把计算后的值存到缓存里面。并把结果返回。
结束
其实里面还有很多知识点含糊不清,像Map和闭包的都没有讲到,后面会有单独的专栏来讲Map和闭包的知识点这些。