要想理解原理就得看源码,最近网上也找了好多vue初始化方法(8个init恶魔。。。)

因为也是循序渐进的理解,对initComputed计算属性的初始化有几处看得不是很明白,网上也都是含糊其辞的(要想深入必须深入。。。),所以debug了好几天,才算是有点头绪,现在写出来即帮自己再次理下思路,也可以让大佬指出错误

首先,基本的双向绑定原理就不说了,可以去搜下相关教程,还是要先理解下简单的例子

进入正题,先来看下initComputed的源码结构,这之前还是先放一个例子也好说明

function initComputed (vm, computed) {console.log('%cinitComputed','font-size:20px;border:1px solid black')var watchers = vm._computedWatchers = Object.create(null);// computed properties are just getters during SSRvar isSSR = isServerRendering();for (var key in computed) {var userDef = computed[key];var getter = typeof userDef === 'function' ? userDef : userDef.get;if ("development" !== 'production' && getter == null) {warn(("Getter is missing for computed property \"" + key + "\"."),vm);}//minxing---consoleconsole.log('%cinitComputed 定义watchers[key]=new Watcher(vm getter noop computedWatcherOptions)','color:white;padding:5px;background:black');if (!isSSR) {// create internal watcher for the computed property./*** 熟悉的newWatcher,创建一个订阅者,为了之后收集依赖* 将例子中的num、lastNum和计算属性comNum进行绑定* 也就是说在一个deps中有两个dep,其中的subs分别是* dep1.subs:[watcher(num),watcher(comNum)]* dep2.subs:[watcher(lastNum),watcher(comNum)]* dep3........* 请看前面的例子,页面html中并没有渲染{{lastNum}};按理说就不会执行lastNum的getter* 从而就不会和计算属性进行关联绑定,如果更改lastNum就不会触发dep2的notify()发布* 自然也就不会在页面看到comNum有所变化,但是运行后却不是这样,为什么呢* 这就引出这个initComputed的下面方法了---依赖收集(watcher.prototype.depend)!* 当时也是看了好久才知道这个depend方法的作用,后面再说* 首先先来提个头,就是下面代码中watcher中这个getter* 其实就是function comNum() {return this.num+"-computed-"+this.lastNum;}}* 而这个getter什么时候执行呢,会在Watcher.prototype.evaluate()方法中执行* 所以watcher中的evaluate()与depend()两个方法都与initComputed相关*/watchers[key] = new Watcher(vm,getter || noop,noop,computedWatcherOptions);}// component-defined computed properties are already defined on the// component prototype. We only need to define computed properties defined// at instantiation here.// 经过判断后定义计算属性---(关联到vm的data上面)if (!(key in vm)) {defineComputed(vm, key, userDef);} else {if (key in vm.$data) {warn(("The computed property \"" + key + "\" is already defined in data."), vm);} else if (vm.$options.props && key in vm.$options.props) {warn(("The computed property \"" + key + "\" is already defined as a prop."), vm);}}}
}

defineComputed方法

这个方法比较简单主要就是将计算属性绑定到vm上,重要的下面的createComputedGetter方法

function defineComputed (target,key,userDef
) {console.log('%cdefineComputed','font-size:20px;border:1px solid black')var shouldCache = !isServerRendering();if (typeof userDef === 'function') {sharedPropertyDefinition.get = shouldCache? createComputedGetter(key): userDef;sharedPropertyDefinition.set = noop;} else {sharedPropertyDefinition.get = userDef.get? shouldCache && userDef.cache !== false? createComputedGetter(key): userDef.get: noop;sharedPropertyDefinition.set = userDef.set? userDef.set: noop;}if ("development" !== '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);
}
function createComputedGetter (key) {console.log('createComputedGetter key',key);return function computedGetter () {var watcher = this._computedWatchers && this._computedWatchers[key];if (watcher) {if (watcher.dirty) {watcher.evaluate();}if (Dep.target) {watcher.depend();}return watcher.value}}
}

createComputedGetter方法,主要做了两件事

1 求计算属性的值---利用上面说的调用watcher.evalute()方法,执行watcher中的getter

2 依赖收集绑定,这点最重要,就是上面说过的如果没有在html中对计算属性相关联的data属性(lastNum)进行页面渲染的话,watcher.depend()此方法就会执行这个依赖收集绑定的作用dep.subs[watcher(计算属性),watcher(计算关联属性1),...],这样的话当你更改lastNum就会触发对应的dep.notify()方法发布通知订阅者执行update,进行数据更新了,而如果将watcher.depend()方法注释掉,而页面中将lastNum渲染({{lastNum}}),此时watcher.evalute()会执行watcher.get从而将此计算watcher推入dep.target中,而渲染lastNum执行getter的时候就会将此watcher加入依赖,所以也会将lastNum和计算属性关联到dep中

function createComputedGetter (key) {console.log('createComputedGetter key',key);return function computedGetter () {var watcher = this._computedWatchers && this._computedWatchers[key];if (watcher) {if (watcher.dirty) {console.log('createComputedGetter watcher evaluate===========');//求值watcher.evaluate();}if (Dep.target) {console.log('createComputedGetter watcher depend===========');//依赖收集watcher.depend();}console.log('%ccreateComputedGetter watcher.value is','color:blue;font-size:40px',watcher.value);return watcher.value}}
}

为了更好的说明下,截两张图(都是基于最上面的html配置哦)

图组一

注释掉watcher.depend()方法,此时deps中没有dep:id4
其实dep:id4在内存中已经定义好了但是没有加入到deps中(因为没有进行依赖收集)
而dep:id5和id6就是上面的数组和递归数组中元素的dep

dep:id3 就是

这下是不是很清楚了

图组二

进行依赖收集后的deps

综上,计算属性基本的原理就是这样了,主要是自己的理解,有不对的地方还请指出,哎,还是写代码舒服点,打字描述太累。。。

vue之initComputed模块源码说明相关推荐

  1. 【Vue原理】Diff - 源码版 之 Diff 流程

    写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本 [2.5.17] 如果你觉得排版难 ...

  2. (精品)ssm Java mysql maven vue健康医疗预约系统(源码+系统+mysql数据库+lw文档)

    下载地址:https://download.csdn.net/download/m0_71595576/85519044 项目介绍: (精品)ssm Java mysql maven vue健康医疗预 ...

  3. vue使用computed有参数_【Vue原理】Computed - 源码版

    专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本2.5.17 今天要记录 computed 的源码,有时候想,理 ...

  4. ensp大型网络环境设计与实现_mongodb内核源码设计实现、性能优化、最佳运维系列-网络传输层模块源码实现三...

    1. 说明 在之前的<<Mongodb网络传输处理源码实现及性能调优-体验内核性能极致设计>>和<<mongodb内核源码设计实现.性能优化.最佳运维系列-tran ...

  5. 分布式事务中间件 Fescar—RM 模块源码解读

    2019独角兽企业重金招聘Python工程师标准>>> 前言 在SOA.微服务架构流行的年代,许多复杂业务上需要支持多资源占用场景,而在分布式系统中因为某个资源不足而导致其它资源占用 ...

  6. element 往node里面增加属性值_【Vue原理】Compile - 源码版 之 Parse 属性解析

    写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本 [2.5.17] 如果你觉得排版难 ...

  7. 初始化触发点击事件_【Vue原理】Event - 源码版 之 自定义事件

    专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本[2.5.17] Vue 的自定义事件很简单,就是使用 观察者模 ...

  8. mysql 线程池源码模块_易语言Mysql线程池2.0模块源码

    易语言Mysql线程池2.0模块源码 易语言Mysql线程池2.0模块源码 系统结构:GetThis,初始化,关闭类线程,线程_测试,其他_附加文本,连接池初始化,取mysql句柄,释放mysql句柄 ...

  9. Wifi模块—源码分析Wifi热点扫描2(Android P)

    一 前言 这次接着讲Wifi工程流程中的Wifi热点扫描过程部分的获取扫描结果的过程,也是Wifi扫描过程的延续,可以先看前面Wifi扫描的分析过程. Wifi模块-源码分析Wifi热点扫描(Andr ...

最新文章

  1. urlparse模块(专门用来解析URL格式)
  2. 美权威报告:量子计算十年内无法落地
  3. GridView实现用...代替超长字符串
  4. DELETE ADJACENT DUPLICATES FROM语句的深入研究及应用
  5. redis缓存穿透、缓存击穿、缓存雪崩概念及解决方案
  6. HTML5移动端拖动惯性
  7. 32位 shell.efi x86_Ubuntu 20.04 LTS或不再支持32位x86 (i386)
  8. 颠覆传统,仅银行卡大小充电宝,10000mAh可登机,手机党出门随身必备!
  9. Servlet 处理多种请求应用
  10. python标签使用教程_怎样用Python做标签云
  11. 确认! Python再次夺冠,老码农:崩溃!
  12. 算法高级(43)-过滤垃圾邮件、短信?-朴素贝叶斯算法
  13. 一生一世一双人,半醉半醒半浮生
  14. “通用大模型”趋势下,AI未来当如何?
  15. 程序员必知:平凡而又神奇的贝叶斯方法
  16. 毕业设计开发板-基于C20S单片机恒温开发板
  17. 新生儿取名:撩人于无形的女宝宝名字,任你挑选
  18. 北京实时公交查询——Flutter 入坑实战
  19. Vue小demo—美团注册页面
  20. ubuntu下定时自动备份数据库

热门文章

  1. window下Jekyll+github搭建自己的博客
  2. 深入分析同步工具类之AbstractQueuedSynchronizer
  3. 那些年我们踩过的坑-NSTimer
  4. 《Gabor feature based sparse representation for face recognition with gabor occlusion dictionary》
  5. python3 selenium ie 拒绝连接报错_python Selenium权限错误:[WinError 5]访问被拒绝
  6. 100个MySQL 的调节和优化的提示
  7. 改革春风吹满地,安卓新系统Q上线腾讯WeTest
  8. Composer 安装时要求输入授权用户名密码
  9. spring-boot+spring-session集成
  10. Java使用OpenCV3.2实现视频读取与播放