vue2和vue3的响应式区别
Contents
vue2响应式
vue2响应式的核心是通过defineProperty
来对对象已有的属性值的读取和修改进行劫持(监视/拦截)
对象的响应式实现
// 简单实现
// 假设app为vue实例
const app = {}
const data = {
name: 'zs',
age: 18
}
// 遍历data,将data属性绑定到app上,对属性的读取和修改进行拦截
Object.entries(data).forEach(([prop, value]) => {
let initValue = value;
Object.defineProperty(app, prop, {
get() {
console.log('defineProperty内部监视 执行get')
return initValue
},
set(newValue) {
console.log('defineProperty内部监视 执行set');
initValue = newValue
}
})
})
console.log(app.name); // defineProperty内部监视 执行get zs
app.name = 'ls'; // defineProperty内部监视 执行set
app.sex = '男'; // 不会执行set方法
console.log(app.sex); // 不会执行get方法
数组的响应式实现
通过重写数组的一系列更新元素方法来实现元素的修改劫持
// 简单实现
const obj = {
push() {},
pop() {},
shift() {},
unshift() {},
splice() {},
sort() {},
reverse() {}
}
Object.keys(obj).forEach(key => {
Object.defineProperty(obj, key, {
value(...args) {
console.log('args', args);
return Array.prototype[key].call(this, ...args)
}
})
})
const arr = [];
arr.__proto__ = obj;
arr.push(1, 2); // args[1,2]
console.log(arr[0]); // 1
我们知道arr.__proto__
等于它的构造函数的原型,也就是Array.prototype
,所以arr
可以执行push
,pop
等方法,但是现在arr.__proto__
指向obj,所以arr.push相当于obj.push
用defineProperty
进行监听,obj.push()
就会执行value
函数,通过call
方法进行数组操作
vue3响应式
通过Proxy来拦截对对象本身的操作,包括属性的读写,属性的添加,属性的删除等… 通过Reflect来动态对被代理的对象的相应属性进行特定操作
// 简单实现:
const user = {
name: 'zs',
age: 18
}
const proxy = new Proxy(user, {
get(target, prop) {
console.log('劫持get操作', prop)
return Reflect.get(target, prop)
},
set(target, prop, val) {
console.log('劫持set()', prop, val);
return Reflect.set(target, prop, val)
},
deleteProperty(target, prop) {
console.log('劫持delete', prop);
return Reflect.deleteProperty(target, prop)
},
})
// 读取属性值
console.log(proxy === user);
console.log(proxy.name); // 劫持get() name zs
// 设置属性值
proxy.name = 'ls'; // 劫持set() name ls
proxy.age = 19; // 劫持set() age 19
console.log(user); // { name: 'ls', age: 19 }
// 添加属性
proxy.sex = '男'; // 劫持set() sex 男
console.log(user); //{ name: 'ls', age: 19, sex: '男' }
// 删除属性
delete proxy.sex; // 劫持delete sex
console.log(user); // { name: 'ls', age: 19 }
总结:正是由于vue3使用proxy代理的方式拦截对象本身,所以在vue3中添加/删除属性都是响应式的,通过下标修改数组也是响应式