Vue源码之对象的侦测变化

最近在看深入浅出Vue.js,看了比较重要的前几章节,关于Vue的响应式原理,做几点总结。

1.要追踪对象的属性的修改变化,可以用es5的Object.defineProperty(obj,key,descriptor)和es6的proxy;Vue使用的是Object.defineProperty。

在修改或获取属性值的时候就会触发setter和getter函数,vue就是在这两个函数去收集和触发与变量有关的依赖的。

function defineReactive(obj,key,val){
    Object.defineProperty(obj,'name',{
        enumerable:true,
        configurable:true,
        get:function(){
            return val
        },
        set:function(newVal){
            if(val === newVal) return ;
            console.log('shezhi1')
            val = newVal
        }
    })
}

2.为了降低耦合性,vue把收集依赖这个操作封装成一个类---Dep。Dep会收集和删除依赖,以及通知依赖属性发生改变需要相关的更新操作等。

class Dep{
    constructor(){
        this.subs = [];
    }
    addSub(sub){
        this.subs.push(sub)
    }
    removeSub(sub){
        remove(this.subs,sub)
    }
    depend(){
        if(window.target){
            this.addSub(window.target)
        }
        // window.target = undefined
    }
    notify(){
        if(this.subs.length){
            for(var i =0;i<this.subs.length;++i){
                this.subs[i].update()
            }
        }
    }
}

这里的window.target就是依赖,依赖就是watcher,当属性值改变时通知的就是watcher,而watcher也是一个类

3.Watcher就是依赖,响应式数据的触发更新都是通过watcher的。

class Watcher{
    constructor(vm,expOrFn,cb){
        this.vm = vm;
        //vm是vue实例,expOrFn,cb类似于$watch的第一、二个参数
        if(typeof expOrFn === 'function'){
            this.getter = expOrFn
        }else{
            this.getter = parsePath(expOrFn)
        }
        this.cb = cb;
        this.value = this.get()
    }
    get(){
        //这里把window.target设置为当前Watcher实例
        window.target = this;
        //这里获取值就会触发getter
        let value = this.getter.call(this.vm)
        window.target = undefined;
        return value
    }
    //dep.notify()就会触发update
    update(){
        //把旧的值存起来
        const oldVal = this.value;
        //触发获取新的值
        this.value = this.get();
        //触发回调函数
        this.cb.call(this.vm,this.value,oldVal)
    }
}

4.defineReactive只是对单个属性的,为了让所有的响应式数据都能被绑定依赖,需要Observer,他也是一个类

//Observer将所有属性转换成 getter/setter 的形式来侦测变化,包含数组和对象
class Observer{
    constructor(value){
        this.value = value;if(Array.isArray(value)){
            //数组
        }else{
            this.walk(value)
        }
    }
    //walk针对对象将所有属性转换成 getter/setter 的形式来侦测变化
    walk(obj){
        const keys = Object.keys(obj);
        for(let i=0,l=keys.length;i<l;++i){
            defineReactive(obj,keys[i],obj[keys[i]])
        }
    }
}

这里defineReactive需要改变一下

function defineReactive(obj,key,val){
    // 判断是不是对象,对象再进行Observer实例化
    if(obj && Object.prototype.toString.call(obj)==='Object object'){
        new Observer(obj)
    }
    let dep = new Dep();
    Object.defineProperty(obj,key,{
        enumerable:true,
        configurable:true,
        get:function(){
            dep.depend();
            return val
        },
        set:function(newVal){
            if(val === newVal) return;
            val =  newVal;
            dep.notify()
        }
    })
}

 

posted @ 2019-08-09 21:09  Loughacker  阅读(91)  评论(0)    收藏  举报