|
| 1 | +--- |
| 2 | + title: Vue源码——工具函数cached |
| 3 | + date: 2023-12-23T12:24:22Z |
| 4 | + summary: |
| 5 | + tags: [] |
| 6 | +--- |
| 7 | + |
| 8 | + ## 前言 |
| 9 | +在 Vue 的源码中使用了很多自己封装的通用工具函数, |
| 10 | + |
| 11 | + |
| 12 | + |
| 13 | +## cached 的缓存原理 |
| 14 | +在阅读 Vue 源码过程中我发现它封装了一个有意思的函数,它可以将一个函数的返回值进行缓存,在 Vue 中使用频次也比较高的,有十九次!<u>ps.为了方便阅读,这里 flow 的类型我删掉了</u> |
| 15 | + |
| 16 | +我们来研究研究这个函数怎么做到缓存的: |
| 17 | +``` |
| 18 | +export function cached(fn) { |
| 19 | + const cache = Object.create(null) |
| 20 | + return (function cachedFn (str) { |
| 21 | + const hit = cache[str] |
| 22 | + return hit || (cache[str] = fn(str)) |
| 23 | + }) |
| 24 | +} |
| 25 | +``` |
| 26 | +这是一个高阶函数,传入一个函数,返回的也是一个函数,使用了闭包的原理,维持了 cache 对象不被销毁。 |
| 27 | +首先呢,它声明了一个空的对象,通过传入的参数 str 去访问对象中的 str 属性,将该值赋值给 hit,这个 hit 命名也十分的形象,意为:击、打 |
| 28 | +- 若未击中,也就是 hit 为 undfined,则将传入的函数返回值存入 cache[str] |
| 29 | +- 若击中,也就是已经存入了值,则直接返回这个值 |
| 30 | +光说可能是比较抽象,我们上demo: |
| 31 | + |
| 32 | +``` |
| 33 | +var capitalize = cached(function (str) { |
| 34 | + return str.charAt(0).toUpperCase() + str.slice(1); |
| 35 | +}); |
| 36 | + console.log(capitalize("abc"), "第一次访问"); |
| 37 | + console.log(capitalize("abc"), "第二次访问"); |
| 38 | +``` |
| 39 | +在首次调用时,函数 cached 内部创建一个空的对象 cache,返回一个函数,这个函数里将 cache[str] 赋值给 hit,然后进行返回,此时我们是未击中的。因为闭包的缘故,这个函数被缓存到 cache对象里,不会被销毁,在我们第二次执行时不用再创建一个新的函数,而是直接调用缓存的函数。 |
| 40 | + |
| 41 | +总的来说,这个函数可以将传入函数的参数作为 key,返回值作为 value,存储到闭包对象里。 |
| 42 | + |
| 43 | +## makeMap |
| 44 | +同样是利用闭包的原理,此函数接收一个字符串 str 和一个布尔值 expectsLowerCase,返回一个函数,返回的函数通过参数从 map 中取出 value,如果 expectsLowerCase 为true,取值函数参数字符串无论大小写,都会取出小写 key 的 value。 |
| 45 | +``` |
| 46 | +export function makeMap ( |
| 47 | + str: string, |
| 48 | + expectsLowerCase?: boolean |
| 49 | +): (key: string) => true | void { |
| 50 | + // 创建一个干净的map |
| 51 | + const map = Object.create(null) |
| 52 | + // 将参数切成数组 |
| 53 | + const list: Array<string> = str.split(',') |
| 54 | + // 遍历循环在 map 中增加 key,value 为 true |
| 55 | + for (let i = 0; i < list.length; i++) { |
| 56 | + map[list[i]] = true |
| 57 | + } |
| 58 | +
|
| 59 | + return expectsLowerCase |
| 60 | + ? val => map[val.toLowerCase()] |
| 61 | + : val => map[val] |
| 62 | +} |
| 63 | +``` |
| 64 | + |
| 65 | + |
| 66 | + |
0 commit comments