《VueJS设计与实现》5.6 只读与浅只读

219 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

前文中讲完了如何浅响应与深响应,在vue3中还新增了一个API,就是readonly,直译过来就是只读对象。

最常见的例子就是Props,不管是在vue2还是vue3,Props都是不应该被改变的,也就是只读。如果你这vue中修改了Props,你就会收到一条警告信息,这是vue3中的,vue2也有类似的。

image.png

那么,在vue3中是如何实现这个功能的呢。(vue2的源码我没研究过,有没有研究过的同学评论区稍微讲一下)

我们上一篇文章已经封装了出来了createReactive这个函数,基本结构如下,我们现在再次增加的参数,onlyRead,也是一个布尔类型,为了不影响上一篇封装出来的几个函数,我们让它默认为false

const createReactive = (obj,deepify = true,onlyRead=false)=>new Proxy(obj,{/*省略其他拦截*/})

其实所谓的只读就是不能修改,不能删除,因此我们就需要修改setdeleteProperty。这里setdeleteProperty的操作其实是一样的,我就省略一下了,要不然代码占比太高了。

const warnForReadOnly = (key)=>console.warn(`${key} is readonly`)
const createReactive = (obj,deepify = true,onlyRead=false)=>new Proxy(obj,{
     set(target,key,newVal,receiver){
         if(onlyRead){
             warnForReadOnly(key)
             return true
         }
     }
    /*省略其他拦截*/
})

但是,这时候还有一个问题,当我们读取的时候,默认会追踪依赖,但是对于readonly来说,追踪依赖是多余的,它是不需要变化,也不需要响应的,因此我们需要在get的时候再处理下。在不是readonly的时候再追踪依赖即可

const createReactive = (obj,deepify = true, onlyRead=false)=>new Proxy(obj,{
     get(target,key,receiver){
         if(!onlyRead){
            track(target,key)
         }
         /*省略其他逻辑*/
     }
    /*省略其他拦截*/
})

当然,和之前实现的reactive一样,这样的readonly也只是浅只读,我们也就可以按照之前的递归完善一下,弄一个深只读。

const createReactive = (obj,deepify = true, onlyRead=false)=>new Proxy(obj,{
     get(target,key,receiver){
        /*省略其他逻辑*/
          if(deepify){
              return res
          }
          if(res && typeof res === 'object'){
               return onlyRead ? readonly(res) : reactive(res)
          }
        return res
     }
    /*省略其他拦截*/
})

const readonly = createReactive(obj,true,true)
const shallowReadonly = createReactive(obj,false,true)

这样就是实现了深只读与浅只读。下一章中,作者开始讲解如何代理数组,其实数组在vue中用的非常多,比如v-for中,在我看了这比代理对象更重要。