vue的数据监听简单实现

247 阅读1分钟

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来解决上述问题