这是我参与「第五届青训营」笔记创作活动的第三十二天
对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实现的,在原本的操作(比如赋值等)上添加了自己的逻辑,比如说设置值时通知响应式系统该值发生了变化,然后响应式系统执行相应的操作。
⬆️以上的实现思路,以及响应式系统是在最开始初始化的时候进行遍历的,由此带来三个问题:
-
后面对 对象属性的添加和删除不能被监测到,因此vue2在全局对象vue上特意实现了两个方法,用来解决这两个问题
- this.$set
- this.$delete
-
只有一开始就在data定义的数据才能被响应式化
-
无法监听数组的变化 (不能使用 Object.defineProperty ?个人猜测)
接下来是参杂了个人猜测的部分:
个人认为data() {}下定义的数据是都挂在一个全局的对象(this)下的,然后对该对象进行遍历,以及响应式化,这是我在思考vue2是如何实现非对象属性类型 (比如nubmer, string) 的响应式的猜测。
Vue3中的响应式
在Vue3中,数据响应式是有两种类型:ref、reactive
- 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),侵删)
- 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属性上