vue的数据监听简单实现
// 触发视图更新
function updateView(){
console.log('update view')
}
// 重新定义数组原型
const oldArrProperty = Array.prototype
// 创建一个新对象,并且这个对象的原型指向Array的原型
const arrProto = Object.create(oldArrProperty);
// 扩展新的方法不会影响原型
['push', 'pop', 'shift', 'unshift', 'splice'].forEach((methodName) => {
arrProto[methodName] = function(){
updateView() // 触发视图更新
oldArrProperty[methodName].call(this, ...arguments)
}
})
// 重新定义属性 监听
function defineReactive(target, key, value){
// 深度监听
observer(value)
// 监听对象属性的核心api
Object.defineProperty(target, key, {
get() {
return value
},
set(newValue) {
if(newValue !== value){
observer(newValue)
console.log(value, newValue)
value = newValue
updateView()
}
}
})
}
// 监听对象
function observer(target){
if(typeof target !== 'object' || target === null){
return target
}
// 数组的话 修改原型属性
if(Array.isArray(target)){
target.__proto__ = arrPro
}
// 遍历对象的属性
for(let key in target){
defineReactive(target, key, target[key])
}
}
}
function observer(target){
if(typeof target !== 'object' || target === null){
return target
}
if(Array.isArray(target)){
target.__proto__ = arrPro
}
for(let key in target){
defineReactive(target, key, target[key])
}
}
存在的缺陷
- defineProperty无法监听对象属性的增加和删除,所以在vue中会用到Vue.set(),Vue.delete()
- 如果对象的层级很深,依赖收集的时候需要深层的遍历,会影响性能
- defineProperty无法监听数组的变化,所以上面的代码重写了数组的原型
- Vue3.0使用proxy来解决上述问题