1.什么是响应式?
同步状态下,JavaScript代码是自上而下执行的
let count = 1
let getDouble = n => n * 2
let double = getDouble(count)
consolle.log(count, double) // 1 2
count = 2
double = getDouble(count)
console.log(count, double) // 2 4
double的值是count乘以2得到的结果;如果我们能让getDouble函数随着count的变化而自动执行。那么这就是响应式。
2.Vue的响应式解决方案
(1)Vue2.0使用Object.defineProperty() MDN文档
读取到count属性时会触发get,修改count时会触发set。在触发set时截取,并修改double的值。
let obj = {}
let count = 1
let getDouble = n => n * 2
let double = getDouble(count)
console.log(double) //2
Object.defineProperty(obj, 'count', {
get() {
return count
},
set(val) {
count = value
double = getDouble(value)
}
})
let obj.count = 2
console.log(double) //4
但是在Object.defineProperty()中删除obj.count的时候,set是不执行的,所以double是无法改变的。为了让删除某个数据可以响应式,Vue实现了$set、$delete以及数组变异方法等API。
(2)Vue3.0使用Proxy(reactive)、value setter(ref)来解决。ProxyMDN文档
Proxy更进步的地方是它可以监听整个对象,并且可以删除。其次它还可以监听不存在的属性,以及更丰富的数据结构比如Map、Set。
缺点:兼容不了IE11(被淘汰的laji不用管,还是chorme屌)
如上:读取到count属性时会触发get,修改count时会触发set,delete时会触发deleteProperty。在触发set和delete时截取,并修改double的值。
let obj = {
count: 1
}
let getDouble = n => n * 2
let double = getDouble(obj.count)
let proxy = new Proxy(obj, {
get: (target, prop) => {
return target[prop]
},
set: (target, prop, value) => {
target[prop] = value
if(prop === 'count') {
double = getDouble(value)
}
},
deleteProperty(target, prop) {
delete target[prop]
if(prop === 'count') {
double = NaN
}
}
})
console.log(obj.count, double) // 1 2
proxy.count = 2
console.log(obj.count, double) // 2 4
delete proxy.count
console.log(obj.count, double) // undefined NaN
Vue3.0的ref()使用对象的get、set函数进行监听。这种响应式的方式只能拦截一个属性。
let getDouble = n => n * 2
let _value = 1
let double = getDouble(_value)
let count = {
get value() {
return _value
},
set vlaue(val) {
_value = val
double = getDouble(_value)
}
}
console.log(count.value, double) // 1 2
count.value = 2
console.log(count.vauel, double) // 2 4