Vue2的历史问题
Object.defineProperty()
是可以监听数组的,key
是角标,value
是元素值。
但对数组插入、删除、排序操作时,数据元素的位置会发生移动,造成每个元素的getter、setter
频繁调用,严重影响性能!所以,Vue2
放弃使用监听数组!
function defineReactive(data, key, value) {
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function defineGet() {
return value
},
set: function defineSet(newVal) {
value = newVal
}
})
}
function observe(data) {
Object.keys(data).forEach(key => {
defineReactive(data, key, data[key])
})
}
var arr = ['a', 'b', 'c']
observe(arr)
Object.defineProperty()
的真正问题是:不能对初始化时没有设置的键值做监听!
var arr = [1, 2, 3]
observe(arr)
arr.push(4) // 无法监听角标为 3,元素值为4 的数组元素
var obj = { name: 'Jscript' }
observe(obj)
obj.age = 18 //无法监听 age 属性
这也是为什么会有Vue2
要重写数组的方法,并提供 Vue.set
等API
另外,Object.defineProperty()
需要一开始就初始化递归遍历,循环监听,这也是性能瓶颈之一。
也正是因为这些历史遗留问题,才会有Vue3
Vue3 Proxy
Object.defineProperty()
是重写对象的key
,而 Proxy
只是拦截读写操作。
Vue3
采用 懒代理 解决深度嵌套问题,只需要遍历第一层的属性即可!
function reactive(data) {
return new Proxy(data, {
get(target, key, receiver) {
var res = Reflect.get(target, key, receiver);
if(typeof ref == 'object') {
return reactive(res); // 懒代理
}
return res;
},
set(target, key, value, receiver) {
return Reflect.get(target, key, value, receiver);
}
})
}
对数组做插入、删除、排序操作时,仍然会多次触发 Proxy getter/setter
,那么 Vue3
中做了什么优化呢?
网友评论