Skip to content

Vue源码——工具函数cached #29

Open
@coderInwind

Description

@coderInwind

前言

在 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]
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions