vue2 由于 JavaScript 的限制,Vue 不能检测数组和对象的变化。尽管如此我们还是有一些办法来回避这些限制并保证它们的响应性。 Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的。
Vue2 不能检测以下数组的变动:
- 当你利用索引直接设置一个数组项时,例如:vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:vm.items.length = newLength。
解决
- vue 设置了 7 个变异数组( push 、 pop 、 shift 、 unshift 、 splice 、 sort 、 reverse )的 hack 方法来解决问题。
Vue.set
原因
(把数组的下标当做对象的属性)Object.defineProperty可以监测到数组和下标的变化。
function defineReactive(data, key, value) {
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get() {
console.log(`get key: ${key} value: ${value}`)
return value
},
set(newVal) {
console.log(`set key: ${key} value: ${newVal}`)
value = newVal
}
})
}
function observe(data) {
Object.keys(data).forEach(function(key) {
defineReactive(data, key, data[key])
})
}
let arr = [1, 2, 3]
observe(arr)
"因为性能问题。性能代价和获得的用户体验收益不成正比"。——尤雨溪
vue3 的 proxy
Object.defineProperty 和 Proxy 本质差别是,defineProperty 只能对属性进行劫持,所以出现了需要递归遍历,新增属性需要手动 Observe 的问题。Proxy 直接代理对象,不需要遍历操作。此外,Proxy 支持 13 种拦截操作