1. 响应式的定义
我们都知道,vue是基于javascript的,那我们使用一段javascript代码来描述响应式
let a = 1,b = 1,c;
c = a + b;
console.log(c) // 输出 2
// 改变 a的值
a = 3;
// 重新给c赋值 即把 c = a + b; 再执行一遍c的值才能变为 4
// c = a + b;
// 再次输出c
console.log(c) // 输出 2
看到没有,c的值并没有随着a的值或者b的值的改变而改变,这就不是响应式的。
故本人粗略定义一下 当一个变量依赖于其他变量时,其他任意一个变量的改变,这个变量也会自动做出相应的改变即变量会随着依赖项变量的改变而自动改变。
vue2和vue3的响应式实现有什么区别?
Vue2的响应式是基于Object.defineProperty实现的
Vue3的响应式是基于ES6的Proxy来实现的
vue2
Vue2的响应式是基于Object.defineProperty的,那我就拿Object.defineProperty来举个例子
// 响应式函数
function reactive(obj, key, value) {
Object.defineProperty(data, key, {
get() {
console.log(`访问了${key}属性`)
return value
},
set(val) {
console.log(`将${key}由->${value}->设置成->${val}`)
if (value !== val) {
value = val
}
}
})
}
const data = {
name: '林三心',
age: 22
}
Object.keys(data).forEach(key => reactive(data, key, data[key]))
console.log(data.name)
// 访问了name属性
// 林三心
data.name = 'sunshine_lin' // 将name由->林三心->设置成->sunshine_lin
console.log(data.name)
// 访问了name属性
// sunshine_lin
data.grade = 80;
console.log(data.grade) // 80
data.grade = 90;
console.log(data.grade) // 90
data新增了grade属性,进行访问和设值,但是都不会触发get和set,所以弊端就是:Object.defineProperty只对初始对象里的属性有监听作用,而对新增的属性无效。这也是为什么Vue2中对象新增属性的修改需要使用Vue.$set来设值的原因。
vue3
const data = {
name: '林三心',
age: 22
}
function reactive(target) {
const handler = {
get(target, key, receiver) {
console.log(`访问了${key}属性`)
return Reflect.get(target, key, receiver)
},
set(target, key, value, receiver) {
console.log(`将${key}由->${target[key]}->设置成->${value}`)
// 注意定义 Proxy 代理对象的 set 的时候,要返回 return true 不然报错
// 解决 https://blog.csdn.net/LawssssCat/article/details/104561640
return Reflect.set(target, key, value, receiver)
}
}
return new Proxy(target, handler)
}
const proxyData = reactive(data)
console.log(proxyData.name)
// 访问了name属性
// 林三心
proxyData.name = 'sunshine_lin'
// 将name由->林三心->设置成->sunshine_lin
console.log(proxyData.name)
// 访问了name属性
// sunshine_lin
proxyData.grade = 80; // 将grade由->undefined->设置成->80
console.log(proxyData.grade) // 访问了grade属性 80
proxyData.grade = 90; // 将grade由->80->设置成->90
console.log(proxyData.grade) // 访问了grade属性 90