vue响应式Object代理对象的修改和删除属性

目录
  • 正文
    • set
    • delete

正文

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

set

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

const ITERATE_KEY=symbol()
const p = new Proxy(obj,{
 set(target,key,newVal,receiver){
        const res = Reflect.set(target,key,newVal,receiver)
        trigger(target,key)
        return res
  }
}

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

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

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

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

const trigger = (target,key,type)=>{
    const depsMap = targetMap.get(target)
    if(!depsMap){
        return
    }
    const effects = depsMap.get(key)
    // 再次去重
    const needToRun = new Set()
    if(effects){
        effects.forEach(e=> e!==activeEffect
            ? needToRun.add(e)
            : ''
        )
    }
    if(type === TriggerType.ADD){
        const otherEffects = depsMap.get(ITERATE_KEY)
        if(otherEffects){
            otherEffects.forEach(e=> e!==activeEffect
                ? needToRun.add(e)
                : ''
            )
        }
    }
    if(needToRun.length){
        needToRun.forEach(fn=> fn?.options?.scheduler ? fn.options.scheduler(fn) : fun())
    }
}

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

delete

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

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

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

const TriggerType = {
    SET:'SET',
    ADD:'ADD',
    DEL:'DELETE'
}

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

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

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

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

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

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

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

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

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

(0)

相关推荐

  • Vue中Object.assign清空数据报错的解决方案

    目录 Object.assign清空数据报错的解决 Object中的assign方法 用于对象合并 普通合并 后者覆盖前者 Object.assign()只有一个参数 Object.assign()只有一个参数 Object.assign()只有一个参数 多个参数 对象合并的时候是浅拷贝 Object.assign清空数据报错的解决 想清空Vue中的data数据报错也许是没有改变this指向的原因可以试着用call等方便改变this指向, 例如: Object.assign(this.$data

  • Vue props中Object和Array设置默认值操作

    我就废话不多说,看代码吧~ seller: { type: Object, default() { return {} } } seller: { type: Object, default: function () { return {} } } 当父组件没有传这个值或者值是空时,输出的话,返回: 下面这种是错误的 seller: { type: Object, default: () => {} } 当父组件没有传这个值或者值是空时,输出的话,这时是返回underfind,在template

  • vue props default Array或是Object的正确写法说明

    1.错误写法 demo:{ type:Array, default:[] } eslint语法报错: Invalid default value for prop "demo": Props with type Object/Array must use a factory function to return the default value. 2.正确的写法应该是: demo: { type: Array, default: function () { return [] } }

  • 解决vue props传Array/Object类型值,子组件报错的情况

    问题: Props with type Object/Array must use a factory function to return the default value. 1.在vue中如果当在父组件通过props传Array/Object类型值给子组件的时候 2.如果子组件的props接收default为 ,如下 报错 原因:props default 数组/对象的默认值应当由一个工厂函数返回 解决: 补充知识:vue的props如何传多个参数 vue父作用域将数据传到子组件通过pro

  • vue3响应式Object代理对象的读取示例详解

    目录 正文 读取属性 xx in obj for ... in 正文 从这一章开始,作者将更新深入的讲解响应式,尤其是vue3响应式的具体的实现.其实在前面一章,如果你仔细阅读,你是可以实现一个简单的响应式函数的,类似于@vue/reactive,当然那只是个demo,是个玩具,我能不能在生产环境上去使用的,它差了太多功能和边界条件. 现在,我们才是真正的深入@vue/reactive. 在vue中,obj.a是一个读取操作,但是仔细想来,读取这个操作很宽泛. obj.a // 访问一个属性 '

  • vue中对象的赋值Object.assign({}, row)方式

    目录 对象的赋值Object.assign({},row) Object.assign()需要注意的一个小知识点 对象的赋值Object.assign({}, row) 复制功能,想单独去掉id不传过去,思路设置局部变量,把整个row对象赋值给newData变量,使用 Object.assign({}, row):使用delete方法删除newData中的id copyStep(index,row){         // 将对象赋值给一个变量         let newData = Obj

  • vue响应式Object代理对象的修改和删除属性

    目录 正文 set delete 正文 上一篇文章我们学习了如何代理对象的读取,下面我们学习如何代理对象的修改和删除属性. set set就是修改代理的属性,按照我们之前写的reactive,它大概是这样的 const ITERATE_KEY=symbol() const p = new Proxy(obj,{ set(target,key,newVal,receiver){ const res = Reflect.set(target,key,newVal,receiver) trigger(

  • 详细分析vue响应式原理

    前言 响应式原理作为 Vue 的核心,使用数据劫持实现数据驱动视图.在面试中是经常考查的知识点,也是面试加分项. 本文将会循序渐进的解析响应式原理的工作流程,主要以下面结构进行: 分析主要成员,了解它们有助于理解流程 将流程拆分,理解其中的作用 结合以上的点,理解整体流程 文章稍长,但大部分是代码实现,还请耐心观看.为了方便理解原理,文中的代码会进行简化,如果可以请对照源码学习. 主要成员 响应式原理中,Observe.Watcher.Dep这三个类是构成完整原理的主要成员. Observe,响

  • vue响应式原理与双向数据的深入解析

    了解object.defineProperty 实现响应式 清楚 observe/watcher/dep 具体指的是什么 了解 发布订阅模式 以及其解决的具体问题 在Javascript里实现数据响应式一般有俩种方案,分别对应着vue2.x 和 vue3.x使用的方式,他们分别是: 对象属性拦截 (vue2.x) Object.defineProperty 对象整体代理 (vue3.x) Proxy 提示:以下是本篇文章正文内容,下面案例可供参考 vue-响应式是什么? Vue 最独特的特性之一

  • Vue响应式系统的原理详解

    目录 vue响应式系统的基本原理 1.回顾一下Object.defineProperty的用法 2.实战1:使用 Object.defineProperty 对 person的age属性 进行监听 3.数据代理 4.vue中实现响应式思路 总结 1.Vue中的数据代理: 2.Vue中数据代理的好处: 3.基本原理: 4.vue中实现响应式思路 vue响应式系统的基本原理 我们使用vue时,对数据进行操作,就能影响对应的视图.那么这种机制是怎么实现的呢? 思考一下,是不是就好像我们对数据的操作 被

  • Vue响应式原理详解

    Vue 嘴显著的特性之一便是响应式系统(reactivity system),模型层(model)只是普通JavaScript对象,修改它则更新视图(view). Vue 响应式系统的底层细节 如何追踪变化 把一个普通的JavaScript对象传给Vue实例的data选项,Vue将遍历此对象的所有属性,并使用Object.defineProperty 把这些属性全部转为 getter/setter.Object.defineProperty是仅ES5支持,并无法shim的特性,这也就是为什么Vu

  • 浅谈Vue响应式(数组变异方法)

    前言 很多初使用Vue的同学会发现,在改变数组的值的时候,值确实是改变了,但是视图却无动于衷,果然是因为数组太高冷了吗? 查看官方文档才发现,不是女神太高冷,而是你没用对方法. 看来想让女神自己动,关键得用对方法.虽然在官方文档中已经给出了方法,但是在下实在好奇的紧,想要解锁更多姿势的话,那就必须先要深入女神的心,于是乎才有了去探索Vue响应式原理的想法.(如果你愿意一层一层地剥开我的心.你会发现,你会讶异-- 沉迷于鬼哭狼嚎 无法自拔QAQ). 前排提示,Vue的响应式原理主要是使用了ES5的

  • vue响应式更新机制及不使用框架实现简单的数据双向绑定问题

    最近看到有些人说vue是双向数据绑定的,有些人说vue是单向数据流的,我认为这两种说法都是错误的,vue是一款具有响应式更新机制的框架,既可以实现单向数据流也可以实现数据的双向绑定. 2 单向数据流与数据双向绑定 单向数据流是指model中的数据发生改变时引起view的改变. 双向数据绑定是指model中的数据发生改变时view的改变,view的改变也会引起model的改变. //这个是单向数据流,改变这个input的value值并不能是data中的text属性发生改变. <input type

  • Vue响应式原理的示例详解

    Vue 最独特的特性之一,是非侵入式的响应系统.数据模型仅仅是普通的 JavaScript 对象.而当你修改它们时,视图会进行更新.聊到 Vue 响应式实现原理,众多开发者都知道实现的关键在于利用 Object.defineProperty , 但具体又是如何实现的呢,今天我们来一探究竟. 为了通俗易懂,我们还是从一个小的示例开始: <body> <div id="app"> {{ message }} </div> <script> v

  • 图解Vue 响应式流程及原理

    目录 阅读本文能够帮助你什么? 一.组件化流程 1. 整个new Vue阶段做了什么? 2. 普通dom元素如何渲染到页面? 3. 组件如何渲染到页面? 4. Vue组件化简化流程 二.响应式流程 1. 依赖收集 2. 派发更新 三.彩蛋篇 1. computed依赖收集 2. computed派发更新 3. user Watcher依赖收集 阅读本文能够帮助你什么? 在学习vue源码的时候发现组件化过程很绕? 在响应式过程中Observer.Dep.Watcher三大对象傻傻分不清? 搞不清楚

随机推荐