当前位置: 首页 > Web前端 > vue.js

Vue.js设计与实现学习总结(第4章1)Vue响应式基本思想与实现

时间:2023-03-31 23:54:49 vue.js

响应式数据和副作用函数副作用函数是产生副作用的函数,例如:body使其改变,而其他函数也可以改变并获取body中的文字,也就是说effect函数的执行直接或间接的影响其他函数的执行结果,这是一个sideeffect影响。副作用函数有很多,也很常见,比如改变一个全局变量的值。响应式基本思想constobj={text:'helloworld'}functioneffect(){document.body.innerText=obj.text}obj.text='hellonoworld'如上代码,执行副作用函数effect时会触发obj.text的读取[[GET]]操作,赋值obj.text时会触发set[[SET]]操作,所以读取操作时,副作用函数effect可以存放在一个datastructure,设置的时候可以把副作用函数effect取出来运行,实现了最基本的响应式如下图所示:监听读取和设置操作,可以使用代理对象Prosy来实现://存储副作用函数constbucket=newSet()//原始数据constdata={text:'helloworld'}//处理原始函数数据constobj=newProxy(data,{//拦截读取操作get(target,key){//存储副作用函数effectbucket.add(effect)//返回属性值returntarget[key]},//拦截设置操作set(target,key,newVal){console.log(newVal);//设置属性值target[key]=newVal//取出副作用函数,执行bucket.forEach(fn=>fn())//returntrue表示操作成功returntrue}})虽然目前可以实现,但是还是有很多缺陷。比如这里直接通过名字获取副作用函数。这种硬编码的方法不灵活,副作用函数和操作的目标对象的属性没有建立明确的关系。这时如果读取obj中的属性,就会存储副作用函数。如果设置某个属性,将检索并执行副作用函数。因此,可以使用全局变量来存储副作用属性://FunctionsusedtostoreregisteredsideeffectsletactiveEffect=undefinedfunctioneffect(fn){activeEffect=fnfn()}并使用WeakMap、Map和Set来分开存储:之所以使用WeakMap作为存储副作用函数的容器是因为当WeakMap是对key的弱引用且引用的对象不存在时,会被垃圾回收机制自动回收,防止memoryoverflow//存放副作用函数的桶constbucket=newWeakMap()//用来存放注册的副作用函数letactiveEffect=undefinedfunctioneffect(fn){activeEffect=fnfn()}constdata={text:'helloworld'}constobj=newProxy(data,{//拦截读取操作get(target,key){//没有activeEffect,直接返回if(!activeEffect)returntarget[key]//从'bucket'中返回depsMap根据目标,这也是一个Maptype:key--->effectsletdepsMap=bucket.get(target)//如果depsMap不存在,创建一个新的Map并关联targetif(!depsMap)bucket.set(target,(depsMap=newMap()))//然后根据key从depsMap中获取deps,里面是ASet类型//存储当前key相关的所有sideeffect函数:effectsletdeps=depsMap.get(key)//如果deps不存在,创建一个新的Set,并关联key0if(!deps)depsMap.set(key,(deps=newSet()))//最后将当前激活的副作用函数添加到'bucket'中deps.add(activeEffect)//返回属性值returntarget[key]},//拦截设置操作集(target,key,newVal){//设置属性值target[key]=newVal//根据target从'bucket'中获取depsMap,是key-->effectsconstdepsMap=bucket.get(target)if(!depsMap)return//根据key获取所有的副作用函数effectsconsteffects=depsMap.get(key)//执行副作用函数effects&&effects.forEach(fn=>fn())}})读取操作流程设置操作流动