vue双向数据绑定原理

1.发布订阅者模式

//dep收集订阅者,并通知订阅者调用相关函数
class Dep { 
    constructor() { 
        this.sub=[]
    }
    //收集依赖
    addSub(watcher) { 
        this.sub.push(watcher)
    }
    //通知订阅者
    notify() { 
        this.sub.forEach((watcher) => { 
            watcher.update()
        })
    }
}
//订阅者
class Watcher { 
    constructor(cd) { 
        this.cd=cd
    }
    update() { 
        this.cd()
    }
}
//相关的订阅者
//订阅者1
let w1 = new Watcher(() => {
    console.log('1');
})
//订阅者2
let w2 = new Watcher(() => {
    console.log('2');
})
let dep = new Dep()
//收集依赖
dep.addSub(w1)
dep.addSub(w2)
//当vue察觉到data被赋值时就会调用notify函数,通知订阅者更新数据
dep.notify()

image

那么vue是如何监听到赋值的了?
通过defineProperty进行数据劫持

// vue 如何监听到数据赋值操作的了?通过给每个定义属性设置监听器,那么dep通知订阅者应该在set()函数里
//当监听到数据变化时,dep就会立即通知相关订阅者更新dom
// (new watcher(() => {
//     这里应该传递 一个更新dom的操作
// }))
let obj = {
    age:"12"
}
Object.defineProperty(obj, 'name', {
    enumerable: true,  //是否可以被循环
    configurable: true,//是否可以被配置 delete
    get() {  //getter
        console.log('我被调用了');
    },
    set() { //setter
        console.log('我不是ls');
     }
})
obj.name='jj'

//打印:我不是ls

3.vue内部数据劫持详解

<script>
      const vm=  new vue({
            el:'#app',
            data:{
                name:'ls',
                obj:{
                    age:19
                }
            }
        })
        console.log(vm);
    </script>
class vue {
    constructor(options) { 
        this.$data = options.data,
        observe(this.$data)
    }
    
}
//定义数据拦截函数
function observe(data) { 
    Object.keys(data).forEach((key) => {
        let value = data[key]
        //如果含有子对象,递归遍历
        if (typeof value === 'object') {
            observe(value)
        } else {
            Object.defineProperty(data, key, {
            enumerable: true,
            configurable:true,
            set(newVal) {
                return newVal
             },
            get() { 
                
                return value
            }
        })
        }
       
     })
}

image

但以上如果重新给obj赋值:vm.$data.obj={sex:1}
obj里的sex是没有set() 和get()的
image
所以我们应该在set()在调用一下observe()

4.vue如何将数据编译到模板上的?

posted @ 2022-04-10 23:10  Kira的学习笔记  阅读(21)  评论(0编辑  收藏  举报