vue中 数据驱动视图更新,是通过数据监听实现,也就是响应式
在vue2中通过 Object.defineProperty实现响应式,实现思路如下
- 监听对象,深度监听通过递归
- 数组监听通过重写数组原型方法
// 重新定义数组原型 const oldArrayPrototty = Array.prototype; // 创建新对象,原型指向oldArrayPrototty,再扩展新的方法不会影响原型 const arrProto = Object.create(oldArrayPrototty); ['push', 'pop', 'shift', 'unshift', 'splice', 'join'].forEach(methodName => { arrProto[methodName] = function() { console.log('数组更新'); return oldArrayPrototty[methodName].call(this, ...arguments); // Array.prototype[methodName].call(this, ...arguments); 调用数组的原型方法 } }) function defineReactive(target, key, value) { observer(value);// 深度监听 Object.defineProperty(target, key, { get() { return value }, set(newValue) { if (newValue !== value) { value = newValue; observer(newValue);// 深度监听 console.log('数据更新'); } } }) } function observer(target) { if (typeof target !== 'object' || target == null) return target; // 数组监听处理 if (Array.isArray(target)) { target.__proto__ = arrProto; } for(let key in target) { // 过滤原型属性 if (target.hasOwnProperty(key)) { defineReactive(target, key, target[key]); } } } let data = { arr: [100, 200, 300], name: '张三'}; observer(data); data.arr.pop(); data.name = '李四';
vue3 通过 proxy 响应式
function reactive(target) { if (typeof target !== 'object' || target === null) { return target; } const proxyConfig = { get(target, key, receiver) { // 只处理本身属性,不处理原型属性 const ownkeys = Reflect.ownKeys(target); if (ownkeys.includes(key)) { // 监听 console.log('get', key); } const result = Reflect.get(target, key, receiver); // 深度监听 - 性能提升,在get的时候才递归 return reactive(result); }, set(target, key, val, receiver){ // 重复数据不处理 if (val === target[key]) { return true; } const result = Reflect.set(target, key, val, receiver); const ownkeys = Reflect.ownKeys(target); if (ownkeys.includes(key)) { console.log('已有的key', key); } else { console.log('新增的key', key); } return result; },// 删除 deleteProperty(target, key, val) { const result = Reflect.deleteProperty(target, key); console.log('delete', key); return result; } } return new Proxy(target, proxyConfig);; }