深入浅出Vue.js阅读——变化侦测相关API的实现原理——vm.$delete

vm.$delete

  vm.$delete的作用是删除数据中的某个属性。由于Vue.js的变化侦测是使用Object.defineproperty实现的,所以数据是使用delete关键字删除的,那么无法发现数据发生了变化。为了解决这个问题,Vue.js提供了vm.$delete方法来删除数据中的某个属性,并且此时Vue.js可以侦测到数据发生了变化。

1. 用法

vm.$delete(target,key)

  • 参数
    • {Object | Array} target
    • {string | number} key/index
  • 用法:
      删除对象的属性。如果对象是响应式的,需要确保删除能触发视图更新。这个方法主要用于避开Vue.js不能检测到属性被删除的限制。
      目标对象不能是Vue.js实例或Vue.js实例的根对象数据。

2. 实现原理

  vm.$delete方法是为了解决变化侦测的缺陷。 它帮助我们在删除属性后自动向依赖发送消息,通知Watcher数据发生了变化。
  在Vue.js的原型上挂载$.delete方法:

import { del } from '../observer/index'
Vue.prototype.$delete = del;

  del函数:

export function del(target,key){
    const ob = target.__ob__;
    delete target[key];
    ob.dep.notify();
}

  处理遇到数组的情况:

export function del(target,key){
    if(Array.isArray(target) && isValidArrayIndex(key)){
        target.splice(key,1)
        return
    }
    const ob = target.__ob__;
    delete target[key];
    ob.dep.notify();
}

  数组的处理逻辑和vm.$set差不多。因为只需要处理删除的情况,所以只需要使用splice将参数key所指定的索引位置的元素删除。因为使用了splice方法,数组拦截器会自动向依赖发送通知。
  与vm.$set一样,vm.$delete也不可以在Vue.js实例或Vue.js实例的根数据对象上使用。

export function del(target,key){
    if(Array.isArray(target) && isValidArrayIndex(key)){
        target.splice(key,1);
        return;
    }

    const ob = target.__ob__;

    // 新增
    if(target._isVue || {ob && ob.vmCount}){
        process.env.NODE_ENV !== 'production' && warn(
            'Avoid deleting properties on a Vue instance or its root $data ' + 
            '- just set it to null.'
        )
        return;
    }
    
    delete target[key];
    ob.dep.notify();
}

  新增代码解读:如果target上有_isVue属性(targetVue.js实例)或者ob.vmCount数量大于1(target是根数据),则直接返回,终止程序继续执行,并且如果是开发环境,会在控制台发出警告。
  如果删除的这个key不是target自身的属性,就什么都不做,直接退出程序执行:

export function del(target,key){
    if(Array.isArray(target) && isValidArrayIndex(key)){
        target.splice(key,1);
        return;
    }
    const on = target.__ob__;
    if(target._isVue || {ob && ob.vmCount}){
        process.env.NODE_ENV !== 'production' && warn(
            'Avoid deleting properties on a Vue instance or its root $data ' + 
            '- just set it to null.'
        )
        return;
    }

    // 如果key不是target自身的属性,则终止程序继续执行  
    if(!hasOwn(target,key)){
        return;
    }
    
    delete target[key];
    ob.dep.notify();
}

  如果删除的这个keytarget中不存在,不需要执行删除操作,也不需要向依赖发送通知。
  判断target是不是一个响应式数据,也就是说判断target上存不存在__ob__属性。只有响应式数据才会发送通知,非响应式数据只需要执行删除操作即可。
  如果数据不是响应式的,则使用return语句阻止执行发生通知的语句:

export function del(target,key){
    if(Array.isArray(target) && isvalidArrayIndex(key)){
        target.splice(key,1);
        return;
    }
    const on = target.__ob__;
    if(target.isVue || {ob && observable.vmCount}){
        process.env.NODE_ENV !== 'production' && warn(
            'Avoid deleting properties on a Vue instance or its root $data ' + 
            '- just set it to null.'
        )
        return;
    }
    if(!hasOwn(target,key)){
        return;
    }
    delete target[key];

    // 如果ob不存在,则直接终止程序
    if(!obj){
        return;
    }
    ob.dep.notify();
}

  在删除属性后判断ob是否存在,如果不存在,则直接终止程序,继续执行下面发送变化通知的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值