【重学前端框架】Vue中的视图更新原理(一)

前言

Vue2.0中的响应式处理(数据改变视图改变)的核心是Object.definedProperty。

data中的变量才是响应式变量,但对于对象类型的变量,给其添加新的属性或删除属性时,视图不能响应到值的变化;对于数组类型的变量,通过数组下标修改属性值,视图不是不能响应到值的变化,通过push、pop、splice等方法修改数组的值,视图能够响应值的变化。为什么是这样的规则?先从Object.definedProperty的使用规则开始说起。

Object.definedProperty的使用规则

1、给{}类型对象的属性重新定义规则

function defineReactive(obj, key, val) {
        Object.defineProperty(obj, key, {
            enumerable: true, // 可枚举
            configurable: true, // 可写
            get: function() {
                console.log('get');
                return val;
            },
            set: function(newVal) {
                // 设置时,可以添加相应的操作
                console.log('set:', val);
                val += newVal;
            }
        });
    }
    let obj = {name: '成龙大哥', say: ':其实我之前是拒绝拍这个游戏广告的,'};
    Object.keys(obj).forEach(k => {
        defineReactive(obj, k, obj[k]);
    });
    obj.say = '后来我试玩了一下,哇,好热血,蛮好玩的'; //会触发set
    obj.age = 20 //不会触发set
    console.log(obj.name + obj.say, obj);

对于新增的对象属性不会触发set方法。

2、给数组[]类型对象的属性重新定义规则

function defineReactive(obj, key, val) {
        Object.defineProperty(obj, key, {
            enumerable: true, // 可枚举
            configurable: true, // 可写
            get: function() {
                console.log('get');
                return val;
            },
            set: function(newVal) {
                // 设置时,可以添加相应的操作
                console.log('set:', val);
                val += newVal;
            }
        });
    }
   
    let arr = [1,2,3,4,5];
    arr.forEach((v, i) => { 
        defineReactive(arr, i, v);
    });
    arr[0] = 'oh nanana'; // 触发set
    arr.push(6) // 不会触发set
    console.log(arr)
    
    let arr2 = [{name: '1'},{name: '2'}, {name: '3'}];
    arr2.forEach((v, i) => { 
        defineReactive(arr2, i, v);
    });
    arr2.forEach((v, i) => { 
        v.status= true // 不会触发set
    });
    arr2.forEach((v, i) => { 
        v.name = true // 不会触发set
    });
    
    arr2[0] = {name: 2} // 会触发set
    arr2.splice(1,1,{name: 111}) // 会触发set
    arr2.push({name: 'tt'}) // 不会触发set
    arr2.length = 2 // 不会触发set

初始化时会将data中的值通过defineProperty设置为响应式,当给变量赋值时就会触发变量对应的set方法,从而调用视图更新的函数。

这里要说的是Object.definedProperty是可以通过数组下标修改值之后触发对应的set方法的,通过push、pop等方法修改数组的值之后是不会触发set方法。

但是Vue中考虑到性能问题,对于数组类型的数据改变自己定义了一套触发响应的规则,通过数组下标修改数组的值是不会触发视图更新的,但是通过push、pop、shift、unshift等方法修改数组的值是可以触发视图更新的。

Vue官方说法不会触发视图更新的情况:

1、对于数组对象

【重学前端框架】Vue中的视图更新原理(一)_第1张图片

2、对于{}对象

【重学前端框架】Vue中的视图更新原理(一)_第2张图片

Vue对数组做了哪些处理呢?

默认的Object.definedProperty中,对于操作数组的方法,默认只有利用数组中的splice修改数组值时可以触发set(splice(1, 1, value), 相当于通过数组下标修改属性值)。

但因为Vue做了处理,以下变异方法修改数组的值都可以触发视图的更新。

【重学前端框架】Vue中的视图更新原理(一)_第3张图片

vue究竟对数组如何做的处理呢?见下一节

参考资料:

记一次思否问答的问题思考:Vue为什么不能检测数组变动

你可能感兴趣的:(vue.js,前端,javascript)