美文网首页
vue中的变化检测问题

vue中的变化检测问题

作者: frank_松 | 来源:发表于2020-03-17 22:19 被阅读0次

    从vue通过Object.defineProperty方法劫持数据可知,vue是监听不到对象属性的增加或删除的,因为这些属性没有被劫持。想要监听数据变化,我们就要将其转换为响应式,这时候可以用this.$set(data, key, value)。

    这个$set里面做了什么?

    一、 给一个对象新增属性
    我们将源码逻辑简化:

    set(target, key, val) {
        ...
        const ob = target._ob_; // 获取对象的_ob_属性,它为劫持数据时创建的observer实例
        ...
        defineReactive(obj, key, val); // 通过definedReactive方法劫持属性,将其转换为响应式
        ob.dep.notify(); // 手动让发布者发送消息,通知订阅者进行更新
        return val;
    }
    

    二、给一个数组的一个位置添加元素

    set(target, key, val) {
        ...
        if (Array.isArray(target)) { // 判断是数组
            target.length = Math.max(target.length, key); // 更新数组长度
            target.splice(key, 1, val); // 通过splice方法向数组指定位置插入元素
            return val;
        }
        ...
    }
    

    或许有人会问了,splice方法会改变原始数组,但是不改变数组在堆内存中的地址,为毛可以通过splice插入元素的方式触发订阅者更新?其实vue内部将数组原型中的方法篡改了,主要做了什么呢?

    我们先列举出会改变原始数组的原型方法

    const methods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
    

    源码中依次遍历这些原型方法,改写其逻辑。主要是:首先获取原型方法执行后的返回值,然后通过数组的“ob”属性发出消息通知订阅者更新,然后将值返回。当使用splice,push,unshift这三个方法时,会额外对新增的元素做一次劫持。

    由于原型方法已经被篡改了,只要使用这些方法修改数组,就会触发响应。

    注:
    1、直接修改数组某个索引的元素触发响应,arr[index] = newVal;
    2、修改数组的长度length不会触发更新, arr.length = newVal;

    相比大家也明白的原因,不在阐述。有问题请指出,谢谢!

    相关文章

      网友评论

          本文标题:vue中的变化检测问题

          本文链接:https://www.haomeiwen.com/subject/cwnzehtx.html