前端面试常见问题-手写实现vue数据监听

前端面试常见问题-手写实现vue数据监听

​ 面试最常问到的问题之一,前端框架vue的实现机制,很多同学都能侃侃而谈,vue实现数据双向绑定主要是:采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应监听回调。但是理解了不一定自己能实现,所以还是要手动实现才能理解更深刻。

​ 话不多说,直接开始。首先定义一个要监听的对象

let dog = {name:'小花', age:'2'} 

​ 上面只是一个普通的js 对象,它的属性变化 可以直接使用 dog.name = ** dog.age=** 来改变,我们现在使用 Object.defineProperty() 来实现对对象的监听。

let dog = {}
let ageNum = '2'
Object.defineProperty(dog,'age',{
    enumerable:true,
    configurable:true,
    get(){
        console.log('age属性被读取了')
        return ageNum
    }
    set(newVal){
        console.log('age属性被修改了')
        return newVal
    
    }
})

​ 通过defineProperty 给 dog 对象定义了一个 属性age,并把这个属性定义了get 和 set方法监听,当该属性被读取或者修改的时候触发get()和 set() 方法。但是一个对象会有很多个属性,我们现在只能监测到 age属性,要一个一个去监听显然不现实,而且还会有很多新增属性,所以我们使用 递归的方式来实现所有属性的监听。

/**
 * 定义Observer类通过递归的方式把一个对象的所有属性都转化成可观测对象
 */
export default Observer{
    constructor(value){
        this.value = value
        // 表示此对象已被设置监听
        def(value,'_observered',this) 
        if(Array.isArray(value)){
            //如果是数组 特殊处理
        }else{
            // 执行监听方法
            this.listen(value)
        }
    }
    listen(obj:Object){
        const keys = Object.keys(obj)
        // 遍历把属性设置监听
        for(let i in keys){
            defineAttr(obj, keys[i])
        }      
    }
   
}
// 给对象设置监听方法
function defineAttr(obj,key,value){
    // 判断 如果参数只有两个 则返回原始值
    if(arguments.length===2){
        value = arguments[key]
    }
    if(typeof value === 'object'){
        new Observer(value)
    }
    Object.defineProperty(obj,key,{
        enumerable:true,
        configurable:true,
        get(){
            console.log(`${key}属性被读取了`)
            return value
        }
        set(newVal){
            console.log(`${key}属性被修改了`)
            return newVal
        
    }
    })
}

​ 在以上代码中,我们定义一个Observer类,用它使普通对象变为可检测对象,把已经设置为响应式的对象设置一个 _observered 属性表示已经被监听,避免重复操作,当对象的属性还是对象时使用 new Observer(value) 递归来检测子对象,这样子所有的对象和子属性对象都成为了 setter和 gerrer模式了。现在我们这样定义对象即可实现属性监测。

let dog = new Observer({
    name:'小花',
    age:'2'
})

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容