这是我以前被问到的一个问题,被问以前没有想过,被问到的时候很懵😯 vue2的数据双向绑定是用的这个Object.defineProperty,vue3会用proxy实现数据劫持。那vue3为何会这么作呢?vue
这个问题我以前试着描述过不少次,可是由于都自认为不够清楚。 vue是利用数据劫持结合发布订阅模式实现的数据双向绑定。在vue的实现里面,简单来讲有四部分:数组
1.Object.defineProperty的第一个缺陷,没法监听数组变化。 可是vue中是能够监听数组的变化的,那他是怎么实现的呢?使用了如下八种方法:浏览器
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
复制代码
实现示例参考:性能优化
const aryMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
const arrayAugmentations = [];
aryMethods.forEach((method)=> {
// 这里是原生Array的原型方法
let original = Array.prototype[method];
// 将push, pop等封装好的方法定义在对象arrayAugmentations的属性上
// 注意:是属性而非原型属性
arrayAugmentations[method] = function () {
console.log('我被改变啦!');
// 调用对应的原生方法并返回结果
return original.apply(this, arguments);
};
});
let list = ['a', 'b', 'c'];
// 将咱们要监听的数组的原型指针指向上面定义的空数组对象
// 别忘了这个空数组的属性上定义了咱们封装好的push等方法
list.__proto__ = arrayAugmentations;
list.push('d'); // 我被改变啦! 4
// 这里的list2没有被从新定义原型指针,因此就正常输出
let list2 = ['a', 'b', 'c'];
list2.push('d'); // 4
复制代码
以上代码参考:这里bash
2.Object.defineProperty的第二个缺陷,只能劫持对象的属性,所以咱们须要对每一个对象的每一个属性进行遍历,若是属性值也是对象那么须要深度遍历,显然能劫持一个完整的对象是更好的选择。app
1.proxy能够直接监听数组的变化; 2.proxy能够监听对象而非属性.它在目标对象以前架设一层“拦截”,外界对该对象的访问,都必须先经过这层拦截,所以提供了一种机制,能够对外界的访问进行过滤和改写。 Proxy直接能够劫持整个对象,并返回一个新对象。dom
本文参考:参考资料1mvvm