手写Vue之MyObserver

在实例化Vue的时候,会实例化出Observer,Observer的作用就是给数据域的所有数据进行重新定义。

observer的代码结构:

 

构造方法

ObserveAllPropertyInData

该方法会遍历整个数据域,对数据域中的每个属性进行重新定义。

defineReactive:

 

可以看到,定义里面多了Dep等对象,这个我们放在Watcher,也就是数据劫持那一章说

/**
 * @param _MyData data域(被代理的真实数据域)
 * @constructor
 */
function Observer(_MyData) {
    this.ObserveAllPropertyInData(_MyData);
}

Observer.prototype = {
    /**
     *  不断递归data,一直到value类型不为object
     *  然后对每个属性进行defineProperty
     * @param _MyData data域(被代理的真实数据域)
     * @constructor
     */
    ObserveAllPropertyInData:function(_MyData) {
        let me = this;
        if( !_MyData || typeof _MyData !== 'object'){
            return ;
        }
        Object.keys(_MyData).allKeys.forEach(function (key) {
            me.ObserveAllPropertyInData(_MyData[key]);
            let val = _MyData[key];
            me.defineReactive(_MyData, key, val);// 数据域(动态变化的引用) 当前的key 当前的val
        })
    },
    /**
     * @param OldObj    当前递归到的数据域
     * @param key       对应的key
     * @param OldVal    key对应的val
     */
    defineReactive:function (OldObj, key, OldVal) {
        let val = OldVal;// 当前数据域的val 如果是对象,那么这个OldVal就是一个对象
        let dep = new Dep();
        // 把当前数据域对应的Dep放入全局Dep数组中
        Dep.testCntent.push(dep);
        // 对当前数据域进行重新定义
        Object.defineProperty(OldObj,key,{
            configurable:false,
            enumerable:true,
            set:function (NewVal) {
                if(val === NewVal)
                    return val;
                // 这里采取的方法是,先把val取出来,然后set的话不要使用OldObj[key]=xxx,避免死循环
                val = NewVal;
                new Observer(NewVal);
                // 这里只会触发就是说,给NewVal里面的所有属性 重新定义 并且 加一个Dep
                // 更新该key下面的所有watcher【watcher和dep的关系在compile阶段建立,如果那个阶段没建立成功,那么这里也不会更新】
                // 更新原则:只更新建立了联系,并且属性名不变的watcher,对于那些后来才加上的属性,一概不理会
                // 你可以利用这个更新原则的漏洞,先写好一个不存在的属性的表达式,相当于占个位,后面再补上去,也是可以的,
                // 因为watcher已经关联上了
                // 这里有一个需要注意的话,被覆盖掉的属性,虽然存在watcher关联,但是重新解析表达式,会得到一个undefined,
                // 结果更新到页面就为空字符了
                dep.notify();
            },
            get:function () {
                /**
                 *   这里有两种情况调用
                 *   1.普通调用,target为null
                 *   2.关联dep和watcher调用,target不为null
                 */
                if(Dep.target){
                    Dep.target.addDep(dep);
                }
                return  val;
            }
        })

    }
}

Dep.testCntent = [];
Dep.target = null;
Dep.id = 0;
function Dep(){
    this.DepId = Dep.id++;
    this.subs = [];
}

// 重复管理
Dep.prototype = {
    AddWarcher:function (watcher) {
        this.subs.push(watcher);
    },
    // 唤醒所有watcher
    notify:function () {
        this.subs.forEach(function (Watcher) {
            // 调用watcher,重新解析表达式,得到最新的值,更新到界面上
            Watcher.Update();
        })
    }
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值