当前位置: 首页 > Web前端 > JavaScript

简单的响应式实现(一)

时间:2023-03-26 21:31:47 JavaScript

设置addFn函数和fnList函数数组constfnList=[]//fnarrayfunctionaddFn(fn){//添加fn到fnListfnList.push(fn)}constobj={//target对象名称:'lisa'}//fn-1addFn(()=>{console.log('firstfn')})//fn-2addFn(()=>{console.log('secondfn')})obj.name='peter'fnList.forEach(fn=>{fn()})上面代码中的fnList用来存放属性变化时要执行的函数。addFn函数是将依赖属性的函数添加到fnList函数数组中。但是,你会发现它还没有完成,它仍然是手动调动的。下面逐步完善。设置一个依赖类我们可以专门设置一个依赖类来添加和调用依赖函数。classDepend{constructor(){this.fnList=[]}addDependFn(fn){this.fnList.push(fn)}notify(){this.fnList.forEach(fn=>fn())}}constdepend=newDepend()constobj={name:'lisa'}depend.addDependFn(()=>{console.log('firstfn')})depend.addDependFn(()=>{console.log('secondfn'')})obj.name='peter'depend.notify()这时候我们已经封装了一系列的操作,但是现在还是需要手动调用。使用Proxy和Reflect的处理我们可以使用Proxy来代理目标对象,然后使用Reflect来对该对象进行操作。classDepend{constructor(){this.fnList=[]}addDependFn(fn){this.fnList.push(fn)}notify(){this.fnList.forEach(fn=>fn())}}constdepend=newDepend()constobj={name:'lisa'}constproxyObj=newProxy(obj,{get(target,key,receiver){returnReflect.get(target,key,receiver)},set(目标,键,newValue,receiver){depend.notify()Reflect.set(target,key,newValue,receiver)}})depend.addDependFn(()=>{console.log('firstfn')})depend.addDependFn(()=>{console.log('secondfn')})proxyObj.name='peter'此时,当objProxy中的属性值出现时,会被setcatcher监听,notify()方法叫做。使用Map和WeakMap进行数据存储,我们可以进行如下图所示的存储管理。WeakMap存储所有“响应式”对象,而map存储对象中的属性。根据上图绘制的存储结构,我们可以组织我们的代码:.fnList.forEach(fn=>fn())}}//创建obj中属性name和obj的依赖对象constdependObjName=newDepend()constdependObjAge=newDepend()constobj={name:'lisa',age:18}//创建一个info中属性address的依赖对象constdependInfoAddress=newDepend()constinfo={address:'sichuan'}//创建一个map来存储obj中每个属性的dependconstmapObj=newMap()mapObj.set('name',dependObjName)mapObj.set('age',dependObjAge)//创建一个map来存储info中每个属性的dependconstmapInfo=newMap()mapInfo.set('address',dependInfoAddress)//创建一个weakMap来存储obj和infomapconstallMap=newWeakMap()allMap.set(obj,mapObj)allMap.set(info,mapInfo)//objproxyconstproxyObj=newProxy(obj,{得到(目标,密钥,接收者){returnReflect.get(target,key,receiver)},set(target,key,newValue,receiver){constmap=allMap.get(target)//获取存储的objmapconstdepend=map.get(key)//获取当前key所对应的depend.notify()Reflect.set(target,key,newValue,receiver)}})//infoproxyconstproxyInfo=newProxy(info,{get(target,key,receiver){returnReflect.get(target,key,receiver)},set(target,key,newValue,receiver){constmap=allMap.get(target)//获取存储的obj的mapconstdepend=map.get(key)//获取当前key所对应的depend.notify()Reflect.set(target,key,newValue,receiver)}})//objnamedependfndependObjName.addDependFn(()=>{console.log('obj1namefirstfn')})dependObjName.addDependFn(()=>{console.log('obj1namesecondfn')})//objagedependfndependObjAge.addDependFn(()=>{console.log('objagefirstfn')})dependObjAge.addDependFn(()=>{console.log('objagesecondfn')})//信息地址依赖fndependInfoAddress.addDependFn(()=>{console.log('infoaddressfirstfn')})proxyObj.name='peter'proxyObj.age=18proxyInfo.address='重庆'我们也可将proxy中获取depend对象的步骤封装成一个函数:/****@param{*}target目标对象*@param{*}对象中key属性名*@returns对应的depend对象key*/functiongetDepend(target,key){//当map和depend不存在时创建的目的:避免undefined.notify()报错letmap=allMap.get(target)//获取对应的maptotargetif(!map){map=newMap()//如果获取的map是undefined,则创建一个mapallMap.set(target,map)}letdepend=map.get(key)//获取keyvalue对应的depend对象if(!depend){depend=newDepend()//如果获取到的depend是undefined,则创建一个depend对象map.set(key,depend)}returndepend}现在我们可以当对象中的值被外界修改,依赖函数会被执行,但更糟的是依赖函数等内容的集合