经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » Vue.js » 查看文章
vue响应式Object代理对象的修改和删除属性
来源:jb51  时间:2022/8/2 12:45:12  对本文有异议

正文

上一篇文章我们学习了如何代理对象的读取,下面我们学习如何代理对象的修改和删除属性。

set

set就是修改代理的属性,按照我们之前写的reactive,它大概是这样的

  1. const ITERATE_KEY=symbol()
  2. const p = new Proxy(obj,{
  3. set(target,key,newVal,receiver){
  4. const res = Reflect.set(target,key,newVal,receiver)
  5. trigger(target,key)
  6. return res
  7. }
  8. }

细心的朋友应该发现了,我专门把ITERATE_KEY也加进来了,但是在set中并没有使用,难道是多余的?

这里其实有一个小坑,就是如果曾经对对象使用过for ... in,这里会出现2种情况:

  • 如果我们新增了一个属性,那么我们是不是应该重新运行一次for ... in的副作用函数。
  • 如果我们只是修改某个属性而不是新增,那么我们就不应该重新运行for ... in的副作用函数. 所以我们需要判断一下它是新增还是修改
  1. //定义常量,在ts中可以使用枚举
  2. const TriggerType = {
  3. SET:'SET',
  4. ADD:'ADD'
  5. }
  6. const p = new Proxy(obj,{
  7. set(target,key,newVal,receiver){
  8. //判断新增还是修改
  9. const type = Object.prototype.hasOwnProperty.call(target,key)
  10. ? TriggerType.SET
  11. : TriggerType.ADD
  12. const res = Reflect.set(target,key,newVal,receiver)
  13. trigger(target,key,type)
  14. return res
  15. }
  16. }

同时,对应trigger函数中,我们也需要根据type读取ITERATE_KEY对应的副作用函数.

  1. const trigger = (target,key,type)=>{
  2. const depsMap = targetMap.get(target)
  3. if(!depsMap){
  4. return
  5. }
  6. const effects = depsMap.get(key)
  7. // 再次去重
  8. const needToRun = new Set()
  9. if(effects){
  10. effects.forEach(e=> e!==activeEffect
  11. ? needToRun.add(e)
  12. : ''
  13. )
  14. }
  15. if(type === TriggerType.ADD){
  16. const otherEffects = depsMap.get(ITERATE_KEY)
  17. if(otherEffects){
  18. otherEffects.forEach(e=> e!==activeEffect
  19. ? needToRun.add(e)
  20. : ''
  21. )
  22. }
  23. }
  24. if(needToRun.length){
  25. needToRun.forEach(fn=> fn?.options?.scheduler ? fn.options.scheduler(fn) : fun())
  26. }
  27. }

这样,我们只在新增的时候才会调用for ... in的副作用函数。

delete

删除的时候,之前貌似没写过。这里需要注意2个点。

  • 保证属性删除之后才运行副作用,这里从逻辑上讲我们最好先验证这个属性是否存在,避免报错。
  • 删除时也要运行for ... in的副作用函数

因此我们这样定义,给TriggerType新增一个类型DEL

  1. const TriggerType = {
  2. SET:'SET',
  3. ADD:'ADD',
  4. DEL:'DELETE'
  5. }

然后,我们开始拦截删除属性的操作,查一下之前的Proxy内部方法的表,我们可以得知,删除属性对应着deleteProperty方法。

  1. const p = new Proxy(obj,{
  2. deleteProperty(target,key){
  3. //判断属性存在,你总不能删除一个不存在的属性吧
  4. const hadKey = Object.prototype.hasOwnProperty.call(target,key)
  5. const res = Reflect.deleteProperty(target,key)
  6. if(res && hadKey){
  7. trigger(target,key,TriggerType.DEL)
  8. }
  9. return res
  10. }
  11. }

对应trigger函数中,我们小修改一下,其他逻辑不变

  1. // 删除这句
  2. - if(type === TriggerType.ADD){
  3. // 改为
  4. + if([TriggerType.ADD,TriggerType.DEL].includes(type)){

这样就可以实现响应式对象的删除属性。

其实原文中并没有使用Array.includes,但我觉得其实我们应该使用最新的语法,现在浏览器环境对这些新语法支持度已经很好了(如果你要兼容IE当我没说)。

这一篇就完结了,总结一下就是如何对对象的读取属性、修改属性、删除属性进行代理,大概了解vue3中对于对象的处理。

但是这里还没有结束,后续会讲一些边际条件,以及如何合理的响应数据变化和操作,合理也就是优化,尽可能的减少多余的响应。

更多关于vue响应式Object修改删除的资料请关注w3xue其它相关文章!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号