[ 对Vue2,Vue3中的响应式数据的初步探索和一些猜测 | 青训营笔记]

59 阅读2分钟

这是我参与「第五届青训营」笔记创作活动的第三十二天

对Vue2,Vue3中的响应式数据的初步探索 和 一些猜测

Vue2中的响应式

在Vue2中的响应式是通过Object.defineProperty来实现的,这里可能更多的关注的是对象的响应式

(Object.defineProperty 的细节可以参考 Object.defineProperty() - JavaScript | MDN (mozilla.org))``

const person = {};

Object.defineProperty(person, 'age', {
  set (value) {
    console.log('age:',  value);
  },
  get () {
    return 10;
  }
});

console.log(person.name);

(这个例子改造自玩转Vue3:升级你的前端框架 - 木雨Lanse - 掘金小册 (juejin.cn),侵删)

对 对象的响应式实现,不是对 对象这个整体来实现的,而是通过遍历对象每个属性并拦截属性的get, set实现的,在原本的操作(比如赋值等)上添加了自己的逻辑,比如说设置值时通知响应式系统该值发生了变化,然后响应式系统执行相应的操作。

⬆️以上的实现思路,以及响应式系统是在最开始初始化的时候进行遍历的,由此带来三个问题:

  1. 后面对 对象属性的添加和删除不能被监测到,因此vue2在全局对象vue上特意实现了两个方法,用来解决这两个问题

    • this.$set
    • this.$delete
  2. 只有一开始就在data定义的数据才能被响应式化

  3. 无法监听数组的变化 (不能使用 Object.defineProperty ?个人猜测)

接下来是参杂了个人猜测的部分:

个人认为data() {}下定义的数据是都挂在一个全局的对象(this)下的,然后对该对象进行遍历,以及响应式化,这是我在思考vue2是如何实现非对象属性类型 (比如nubmer, string) 的响应式的猜测。

Vue3中的响应式

在Vue3中,数据响应式是有两种类型:ref、reactive

  1. reactive是通过Proxy来实现的,由于Proxy可以劫持整个对象,所以Vue2中的存在的 (不能检测到对象属性的增删,不能检测到数组的变化的问题都被修复了),但同时也带来兼容性的问题,比如老浏览器 (比如IE11) 不支持Proxy特性
const person = {
    name: '小明',
    age: 18
};
const personProxy = new Proxy(person, {
    get: function(target, prop) {
        console.log(`获取了${prop}:`, target[prop]);
        return target[prop];
    },
    set: function(target, prop, value) {
        console.log(`修改了${prop}:`, value);
        target[prop] = value;
    }
});

console.log('name:', personProxy.name); // 获取了name:小明
personProxy.age = 20; // 修改了age:20
person.sex = 'male';

console.log('sex:', personProxy.sex); // 获取了sex:male
personProxy.sex = 'female'; // 修改了sex:female

​ (这个例子引用自玩转Vue3:升级你的前端框架 - 木雨Lanse - 掘金小册 (juejin.cn),侵删)

  1. ref是通过对象本身的get,set方法实现的
const count = {
    _value: 0,
    set value(num) {
        console.log('修改了count:', num);
        this._value = num;
    },
    get value() {
        console.log('获取了count');
        return this._value
    }
}

console.log(count.value); // 获取了count
count.value = 1; // 修改了count: 1

仔细观察后,不难得出ref中 xxx.value的写法是因为ref方法将我们定义的数据放到了一个对象的value属性上