Vue 响应式布局原理解析

class Observe {
    constructor (data) {
        if (!data || typeof data !== 'object') return
        this.data = data
        this.walk()
    }
    walk () {
        Object.keys(this.data).forEach(function(val, key){
            this.propretyRactive(this.data,val,this.data[val])
        }, this)
    }
    propretyRactive(data, key, val){
        //为了保证每层的值都能添加getter,setter方法进行回调
        new Observe(val)
        var dep = new Dep()
        Object.defineProperty(data, key, {
            get (){
                if (Dep.target){
                    dep.addSub(Dep.target)
                }
                return val
            },
            set (newVal) {
                if (newVal !== val) {
                    val = newVal
                    // 为新值添加getter,setter方法
                    new Observe(val)
                    dep.notify()
                }
            }
        })
    }
}
//发布者类
class Dep {
    constructor () {
        this.subs = []
    }
    addSub (sub) {
        if (!this.subs.includes(sub)){
            this.subs.push(sub)
        }
    }
    notify () {
        this.subs.forEach(function(val){
            val.update()
        })
    }
}
Dep.target = null

//订阅者类
class Watcher {
    constructor (vm, keys, updateCb) {
        this.vm = vm 
        this.keys = keys
        this.updateCb = updateCb
        this.value = this.get()
       
    }
    get () {
        Dep.target = this
        var value = this.vm.data
        let key = this.keys.split('.')
        //隐式调用getter方法。从而将订阅者添加到发布者的通知列表
        key.forEach(_key=>{
            value = value[_key]
        })
        Dep.target = null
        return value
    }
    update () {
        let newVal = this.get()
        if (newVal !== this.value){
            this.value = newVal
            this.updateCb.call(this.vm)
        }

    }
}

var data = {
    test: 1,
    testObj: {
        tb1: 1
    }
}

var vm = new Observe(data)

new Watcher(vm, 'test', function(){
    console.dir('test已更新')
})
new Watcher(vm, 'testObj.tb1', function(){
    console.dir('testObj.tb1已更新')
})

data.testObj.tb1 = 2

你可能感兴趣的:(Vue 响应式布局原理解析)