Vue源码系列-6- computed计算属性的实现原理

计算属性默认是有缓存的,内部实现参考源码

src/core/instance/state.js

调用initComputed() 方法,创建 watcher

/**
 *  初始化 computed
 * @param {*} vm 
 * @param {*} computed 
 */
function initComputed (vm: Component, computed: Object) {
  // $flow-disable-line
  // 创建 watcher(lazy为true, 默认 dirty 为true, 默认watcher 不执行)
  const watchers = vm._computedWatchers = Object.create(null)
  // computed properties are just getters during SSR
  const isSSR = isServerRendering()
  
  // 便利 computed 对象中的所有key
  for (const key in computed) {
    // 部分代码略 ....

    // component-defined computed properties are already defined on the
    // component prototype. We only need to define computed properties defined
    // at instantiation here.
    // 如果在组件上不存在这个属性
    if (!(key in vm)) {
      // 定义这些key 到 computed 计算属性上
      defineComputed(vm, key, userDef)
    } 
  }
}

接着看 defineComputed(), 这个方法就是 将属性定义到实例上

// 将属性 定义到 实例上
export function defineComputed (
  target: any,
  key: string,
  userDef: Object | Function
) {
//   const shouldCache = !isServerRendering()
//   if (typeof userDef === 'function') {
//     sharedPropertyDefinition.get = shouldCache
//       ? createComputedGetter(key)
//       : createGetterInvoker(userDef)
//     sharedPropertyDefinition.set = noop
//   } else {
//     sharedPropertyDefinition.get = userDef.get
//       ? shouldCache && userDef.cache !== false
//         ? createComputedGetter(key)
//         : createGetterInvoker(userDef.get)
//       : noop
//     sharedPropertyDefinition.set = userDef.set || noop
//   }
//   if (process.env.NODE_ENV !== 'production' &&
//       sharedPropertyDefinition.set === noop) {
//     sharedPropertyDefinition.set = function () {
//       warn(
//         `Computed property "${key}" was assigned to but it has no setter.`,
//         this
//       )
//     }
//   }
 // 重新定义这些属性到实力上
  Object.defineProperty(target, key, sharedPropertyDefinition)
}

用户取值的缓存处理在 createComputedGetter() 方法中

// 创建getter 当用户取值时,会执行此方法
function createComputedGetter (key) {
  return function computedGetter () {
    const watcher = this._computedWatchers && this._computedWatchers[key]
    // 当用户取值时
    if (watcher) {
      // 如果dirty 为true
      if (watcher.dirty) {
        // 计算结果(同时会进行依赖收集, dirty 改为false)
        watcher.evaluate()
      }
      if (Dep.target) {
        watcher.depend()
      }
      // 如果是false, 直接返回上次计算的结果
      return watcher.value
    }
  }
}

源码逻辑总结:

  1. 调用initComputed()初始化计算属性
  2. 创建 watcher 实例(这个时候,默认lazy为true, dirty 为true, watcher默认不执行)
  3. 调用defineComputed() 方法,将属性定义到 实例上去
  4. 通过createComputedGetter() 这个方法用于用户的取值操作
  5. 在这个方法中,当用户取值时, 会判断 dirty,
    • 如果为true, 调用 watcher.evaluate() 计算结果,并进行依赖收集,dirty变为false
    • 如果为false, 直接返回上次计算的结果
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值