Open
Description
前言
在 Vue 的源码中使用了很多自己封装的通用工具函数,
cached 的缓存原理
在阅读 Vue 源码过程中我发现它封装了一个有意思的函数,它可以将一个函数的返回值进行缓存,在 Vue 中使用频次也比较高的,有十九次!ps.为了方便阅读,这里 flow 的类型我删掉了
我们来研究研究这个函数怎么做到缓存的:
export function cached(fn) {
const cache = Object.create(null)
return (function cachedFn (str) {
const hit = cache[str]
return hit || (cache[str] = fn(str))
})
}
这是一个高阶函数,传入一个函数,返回的也是一个函数,使用了闭包的原理,维持了 cache 对象不被销毁。
首先呢,它声明了一个空的对象,通过传入的参数 str 去访问对象中的 str 属性,将该值赋值给 hit,这个 hit 命名也十分的形象,意为:击、打
- 若未击中,也就是 hit 为 undfined,则将传入的函数返回值存入 cache[str]
- 若击中,也就是已经存入了值,则直接返回这个值
光说可能是比较抽象,我们上demo:
var capitalize = cached(function (str) {
return str.charAt(0).toUpperCase() + str.slice(1);
});
console.log(capitalize("abc"), "第一次访问");
console.log(capitalize("abc"), "第二次访问");
在首次调用时,函数 cached 内部创建一个空的对象 cache,返回一个函数,这个函数里将 cache[str] 赋值给 hit,然后进行返回,此时我们是未击中的。因为闭包的缘故,这个函数被缓存到 cache对象里,不会被销毁,在我们第二次执行时不用再创建一个新的函数,而是直接调用缓存的函数。
总的来说,这个函数可以将传入函数的参数作为 key,返回值作为 value,存储到闭包对象里。
makeMap
同样是利用闭包的原理,此函数接收一个字符串 str 和一个布尔值 expectsLowerCase,返回一个函数,返回的函数通过参数从 map 中取出 value,如果 expectsLowerCase 为true,取值函数参数字符串无论大小写,都会取出小写 key 的 value。
export function makeMap (
str: string,
expectsLowerCase?: boolean
): (key: string) => true | void {
// 创建一个干净的map
const map = Object.create(null)
// 将参数切成数组
const list: Array<string> = str.split(',')
// 遍历循环在 map 中增加 key,value 为 true
for (let i = 0; i < list.length; i++) {
map[list[i]] = true
}
return expectsLowerCase
? val => map[val.toLowerCase()]
: val => map[val]
}