计算计算属性是Vue中常用的一个功能,但你理解它是怎么工作的吗?
拿官网简单的例子来看一下:
& lt; div id=袄印北? & lt; p>原始消息:“{{消息}}”& lt;/p> & lt; p>计算了消息:“{{reversedMessage}}”& lt;/p> & lt;/div> >之前var vm=new Vue ({ 埃尔:“#例子”, 数据:{ 消息:“你好” }, 计算:{//计算getter reversedMessage:函数(){//这个点到vm实例 返回this.message.split (”) .reverse . join () () } } }) >之前
Vue里的计算属性非常频繁的被使用的到,但并不是很清楚它的实现原理,比如:计算属性如何与属性建立依赖关系?属性发生变化又如何通知到计算属性重新计算吗?
关于如何建立依赖关系,我的第一个想到的就是语法解析,但这样太浪费性能,因此排除,第二个想到的就是利用JavaScript单线程的原理和Vue的Getter设计,通过一个简单的发布订阅,就可以在一次计算属性求值的过程中收集到相关依赖。
因此接下来的任务就是Vue源从码一步步分析计算的实现原理。
分析依赖收集实现原理,分析动态计算实现原理。
数据属性初始化getter setter:
//src/观察者/index.js//这里开始转换数据的getter setter,原始值已存入到__ob__属性中 Object.defineProperty (obj,钥匙,{ 可列举的:真的, 可配置:没错, 得到:reactiveGetter函数(){ 常量值=https://www.yisu.com/zixun/getter ?getter.call (obj):瓦尔//判断是否处于依赖收集状态 如果(Dep.target) {//建立依赖关系 dep.depend () … } 返回值 }, 设置:函数reactiveSetter (newVal) { …//依赖发生变化,通知到计算属性重新计算 dep.notify () } }) >之前
//src/核心//state.js实例//初始化计算属性 函数initComputed (vm:组件计算:对象){ …//遍历计算计算属性 (const关键计算){ …//创建观察家实例//创建内部计算属性的观察家。 观察者(例子)=新观察家(vm, getter | |等待,等待,computedWatcherOptions)//创建属性vm。reversedMessage,并将提供的函数将用作属性vm。reversedMessage的getter,//最终计算与数据会一起混合到vm下,所以当计算与数据存在重名属性时会抛出警告 defineComputed (vm、关键,userDef) … } } 导出功能defineComputed(目标:任何关键:字符串,userDef:对象|函数){ …//创建预备方法 sharedPropertyDefinition。得到=createComputedGetter(键) sharedPropertyDefinition。设置=等待 …//创建属性vm。reversedMessage,并初始化getter setter Object.defineProperty(目标、关键、sharedPropertyDefinition) } 函数createComputedGetter(关键){ 返回函数computedGetter () { const观察家=computedWatchers,,this._computedWatchers(例子) 如果(观察者){ 如果(watcher.dirty) {//观察者暴露评估方法用于取值操作 watcher.evaluate () }//同第1步,判断是否处于依赖收集状态 如果(Dep.target) { watcher.depend () } 返回watcher.value } } } >之前无论是属性还是计算属性,都会生成一个对应的观察家实例。
//src/核心/观察者/watcher.js//当通过vm。reversedMessage获取计算属性时,就会进到这个getter方法 get () {//这指的是观察者实例//将当前观察家实例暂存到Dep.target,这就表示开启了依赖收集任务 pushTarget(这) 我们的价值 const vm=this.vm 尝试{//在执行vm。reversedMessage的函调函数时,会触发属性(步骤1)和计算属性(步骤2)的getter//在这个执行过程中,就可以收集到vm。reversedMessage的依赖了 值=https://www.yisu.com/zixun/this.getter.call(虚拟机,虚拟机) }捕捉(e) { 如果(this.user) { handleError (e, vm的getter观察家“$ {this.expression} ") 其他}{ 把e } 最后}{ 如果(this.deep) { 遍历(值) }//结束依赖收集任务 popTarget () this.cleanupDeps () } 返回值 } >之前上面多出提到了dep.depend, dep.notify, Dep.target,那么Dep究竟是什么呢?
深入理解Vue计算计算属性原理