资讯专栏INFORMATION COLUMN

Vue源码解析(三)-computed计算属性&&lazy watcher

CoderStudy / 1938人阅读

摘要:前言源码解析一模版渲染源码解析二双向绑定官网给出的如下结果源码分析判断参数是否包含属性本例中本例中和是函数监听计算属性设置,延迟执行的方法设置可以通过本例方式访问计算属性对象初始化时会针对属性的所有值分别一个对象,在源码解析二中有详细介

前言

1、Vue源码解析(一)-模版渲染
2、Vue源码解析(二)-MVVM双向绑定

demo

官网给出的demo如下

new Vue({ el: "#app", template: `

Original message is: {{ message }}

Computed reversed message:: {{ reversedMessage }}

`, data(){ return { message: "Hello", } }, computed:{ reversedMessage(){ return this.message.split("").reverse().join("") } } }) 结果: Original message: "Hello" Computed reversed message: "olleH"
源码分析
//判断参数是否包含computed属性
if (opts.computed) { initComputed(vm, opts.computed); }

function initComputed (vm, computed) {
   var watchers = vm._computedWatchers = Object.create(null);
   //本例中key=‘reversedMessage’
   for (var key in computed) {
      //本例中userDef和getter是reversedMessage函数
      var userDef = computed[key];
      var getter = typeof userDef === "function" ? userDef : userDef.get;
      //监听计算属性,设置lazy=true,延迟执行watcher的get方法
      watchers[key] = new Watcher(vm,getter,{lazy:true});
      //设置可以通过vm[key](本例vm.reversedMessage)方式访问计算属性
      defineComputed(vm, key, userDef);
   }
}

1、vue对象初始化时会针对computed属性的所有key值分别new一个watcher对象,在Vue源码解析(二)中有详细介绍watcher的原理,当时提到watcher初始化会立即调用一次watcher.get方法,然后实际上可以通过传入{lazy:true}参数来延迟watcher.get方法的执行

var Watcher = function Watcher (vm,expOrFn,options){
    //延迟计算
    this.lazy = options.lazy;
    //还没有计算,所以数据是脏的
    this.dirty = options.lazy;
    this.value = this.lazy
    ? undefined
    //计算getter值和收集依赖
    : this.get();
}

2、defineComputed(vm, key, userDef),将computed属性代理到vm上,通过vm[key]访问computed属性值

function defineComputed (target,key,userDef){
    //userDef是function,getter设为userDef或userDef的值
    if (typeof userDef === "function") {
        //shouldCache是否缓存,这也是使用computed属性最重要的原因,computed值会被缓存起来,而不是每次重新执行函数生成
        sharedPropertyDefinition.get = shouldCache
          ? createComputedGetter(key)
          : userDef;
        sharedPropertyDefinition.set = null;
    //userDef是不是function,getter设为userDef.get,setter设为userDef.set
    } else {
        sharedPropertyDefinition.get = userDef.get
          ? shouldCache && userDef.cache !== false
            ? createComputedGetter(key)
            : userDef.get
          : null;
        sharedPropertyDefinition.set = userDef.set
          ? userDef.set
          : null;
    }
    //,将computed属性代理到vm上,通过vm[key]访问computed属性值
    Object.defineProperty(target, key, sharedPropertyDefinition);
}

function createComputedGetter (key) {
  return function computedGetter () {
      //shouldCache = true时直接返回缓存值watcher.value
      var watcher = this._computedWatchers && this._computedWatchers[key];
      //存在脏数据则重新计算watcher的值
      if (watcher.dirty) {
        watcher.evaluate();
      }
      //直接返回缓存中watcher的值
      return watcher.value
    }
  }
}

3、前面提到watcher.get方法会延迟执行,那么到底啥时执行呢?这又得提到Vue源码解析(二)中的updateComponent方法,由于本例引用了计算属性{{ reversedMessage }},updateComponent中的render函数则会调用vm.reversedMessage,因此触发第二步的sharedPropertyDefinition.get函数,调用 watcher.evaluate(),最终调用watcher.get()来计算watcher的值和收集依赖。(watcher.get方法将监听vm.reversedMessage的watcher对象和发布vm.message变化的dep对象绑定,因此当vm.message变化时,vm.reversedMessage值也会同步变化)
因此watcher.get是在第一次访问vm.reversedMessage对象时调用的,所以如果模版没有用到{{ reversedMessage }}值的话vm.reversedMessage的值是不会被计算的

/**
 * Evaluate the value of the watcher.
 * This only gets called for lazy watchers.
 */
Watcher.prototype.evaluate = function evaluate () {
  this.value = this.get();
  this.dirty = false;
};
双向绑定问题

正好之前看到过一个问题vue.js使用computed计算某个属性后,该属性的双向绑定没了,看了本文的源码后大家应该了解了计算属性用在v-model上应该设置setter方法,例如本例中demo应该这么写:

new Vue({
  el: "#app",
  template: 
  `

Original message is: {{ message }}

Computed reversed message:: {{ reversedMessage }}

`, data(){ return { message: "jixiangwu", } }, computed:{ reversedMessage:{ get(){ return this.message.split("").reverse().join("") }, set(val){ this.message = val.split("").reverse().join("") } } } })

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89612.html

相关文章

  • Vue原理】Computed - 源码

    摘要:被读取,包装的函数触发,第一次会进行计算被调用,进而被调用,被设置为,旧值页面被缓存起来。计算会读取,此时就收集到同时也会保存到的依赖收集器用于下一步。 写文章不容易,点个赞呗兄弟专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧研究基于 Vue版本 【2.5.17】 如果你觉得排版难看,请点击 下面链接 或者 拉到 下...

    solocoder 评论0 收藏0
  • vue源码分析系列之响应式数据(

    摘要:并在内执行了函数,在函数内部,访问了。至此知道了它依赖于。需要根据最新的计算。本例中收集到了依赖并且也被告知观察了他们。文章链接源码分析系列源码分析系列之环境搭建源码分析系列之入口文件分析源码分析系列之响应式数据一源码分析系列之响应式数据二 前言 上一节着重讲述了initData中的代码,以及数据是如何从data中到视图层的,以及data修改后如何作用于视图。这一节主要记录initCo...

    shenhualong 评论0 收藏0
  • [Vue.js进阶]从源码角度剖析计算属性的原理

    摘要:前言最近在学习计算属性的源码,发现和普通的响应式变量内部的实现还有一些不同,特地写了这篇博客,记录下自己学习的成果文中的源码截图只保留核心逻辑完整源码地址可能需要了解一些响应式的原理版本计算属性的概念一般的计算属性值是一个函数,这个函数showImg(https://user-gold-cdn.xitu.io/2019/5/6/16a8b98f1361f6f6); 前言 最近在学习Vue计...

    melody_lql 评论0 收藏0
  • 源码学习VUEWatcher

    摘要:这里面还有一些问题对应的回调函数这就是执行上下文收集依赖同步异步更新所谓的同步更新是指当观察的主体改变时立刻触发更新。 我们在前面推导过程中实现了一个简单版的watcher。这里面还有一些问题 class Watcher { constructors(component, getter, cb){ this.cb = cb // 对应的回调函数,callback...

    sutaking 评论0 收藏0
  • Vue源码解析(二)-MVVM双向绑定&&Watcher介绍

    摘要:前言上一遍文章介绍了模版渲染的实现,这篇文章将继续介绍双向绑定的实现官网如下,当。 前言 上一遍文章介绍了Vue模版渲染的实现(https://segmentfault.com/a/11...),这篇文章将继续介绍双向绑定的实现 demo 官网demo如下,当data。message的值变化,input的value值也会相应的变化;当用户改变input框中的内容时data.messag...

    miya 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<