vue2和vue3响应式原理

66 阅读1分钟

vue2中使用的是 Object.defineProperty 方法对属性进行的监听,对原始对象进行操作

  1. 由于是针对属性的监听,所以每次监听都需要深度遍历对象进行监听属性的变化
  2. 会有效率的损失
  3. 在观察函数中 obj 的初始值都会被监听, 新增的属性无法被监听到;监听的步骤已经结束
const obj = {
    a: 1,
    b: 2,
    c: {
        c1: 20,
        c2: 30,
    },
}

// 判断是否是一个对象
function _isObjeck(v) {
    return typeof v === 'object' && v !== null;
}
function observe(obj) {
    for (const k in obj) {
        let v = obj[k];
        if (_isObjeck(v)) {
            observe(v)
        };
        Object.defineProperty(obj, k, {
            // get 用于读取数据
            get() {
                console.log("读取:", v)
                return v;
            },
            // set 用于修改值
            set(newVal) {
                if (newVal !== v) {
                    console.log(`修改了属性${k}:`, newVal)
                    v = newVal;
                }
            },
        });
    }
}
// 观察
observe(obj)
obj.a = 20;

vue3 使用es6 proxy事件代理对数据代理一个新的对象,通过代理对象通知原始对象

  1. 不再对obj的某个属性进行监听,而是直接监听obj对象
  2. 由于不再是监听属性,所以不用不用遍历对象,直接监听对象
const obj = {
    a: 1,
    b: 2,
    c: {
            c1: 20,
            c2: 30,
    },
}

// 判断是否是一个对象
function _isObjeck(v) {
        return typeof v === 'object' && v !== null;
}

//观察
function observe(obj) {
    const proxy = new Proxy(obj,{
        // target:obj对象  k:key val:修改后得值
        get(target,k) {
            let v = target[k];
            if(_isObjeck(v)){
                v = observe(v);
            };
            console.log("读取:", v)
            return v;
        },
        // 修改值触发set
        set(target,k,val) {
            if(target[k] !== val){
                console.log(`修改了属性${k}:`, val)
                target[k] = val;
            }
        },
        // 删除方法
        deleteProperty(target, property) {
            console.log('53:',target, property)
        }
    })
    return proxy;
}
const proxy = observe(obj);
proxy.c.c1 = 30;

总结

无论是vue2还是vue3,必须要读取的值变成get,set函数,只能通过get,set函数对值进行监听/操作