zoukankan      html  css  js  c++  java
  • 模拟Vue之数据驱动3

    一、前言

    在"模拟Vue之数据驱动2"中,我们实现了个Observer构造函数,通过它可以达到监听已有数据data中的所有属性。

    但,倘若我们想在某个对象中,新增某个属性呢?

    如下:

    那么岂不是,新增的infor属性,以及它的对象属性,没有得到监听。

    此时,应该怎么处理呢?

    通过走读Vue源码,发现他是采用另增属性方法$set实现的。

    就是说,如果我们采用常规方法为对象增加属性(如上),我们没法得知并监控它,所以,我们为每个对象扩展一个$set方法,用于另增属性使用,即可,如下:

    data.user.$set('infor', {msg: 'happy'});

    好了,下面,我们就一同实现这个$set方法吧。

    二、$set方法实现

    首先,我们得创建一个恒定extendObj对象,用于将$set方法绑定在其中。

    你可能会想,为什么我们需要一个extendObj对象呢?直接将$set函数赋值给每个需要监听的对象不就完了么?

    是的,这样也可以,但是随着需求增长,倘若我们又想为每个监听对象扩展其他方法呢?难道又要去Observer里面为对象,一一赋值?

    so,创建恒定extendObj对象,如下:

    const extendObj = {};

    因为,我们将$set绑定到extendObj中,且让$set为不可枚举型,所以会用到Object.defineProperty,固将其提取出来,作为一个方法如下:

    function proxyObject(obj, key, val, enume){
        Object.defineProperty(obj, key, {
            value: val,
            enumerable: !!enume,
            writable: true,
            configurable: true
        });    
    };

    接下来,就是实现$set方法了,整体结构如下:

    proxyObject(extendObj, '$set', function(key, val){
        //this指向extendObj
        if(this.hasOwnProperty(key)){
            return;
        }else{
            /*
              TODO:在extendObj中监听key属性,
              且,若key属性值为对象,再次监听key属性值
            */          
        }    
    });

    看到上面的TODO注释,是否似曾相识,不就是是在“模拟Vue之数据驱动2”遇见过的嘛,通过Observer.prototype.convert监听key属性,通过new Observer再次监听key属性值不就完啦。

    的确,但是一旦这样做了,不就和上面我们提到的“直接将$set赋予监听对象”问题一样嘛,耦合性太大,且随着需求上涨,不易维护。

    固而,在此需要一点小技巧:在observer模块中为每个监听对象赋予一个$Observer属性,其值指向Observer自身实例,如下:

    //observer.js
    p.walk = function(data){
        let keys = Object.keys(data);
        keys.forEach( key => {
            let val = data[key];
            if(typeof val === 'object'){
                new Observer(val);
            }
            this.convert(key, val);
        });
        //$Observer属性指向Observer自身实例
        data.$Observer = this;
    }
    //新增一个observe方法
    p.observe = function(data){
        if(typeof data === 'object'){
            new Observer(data);    
        }    
    }

    好了,这样之后,得$set整体实现如下:

    proxyObject(extendObj, '$set', function(key, val){
        if(this.hasOwnProperty(key)){
            return;
        }else{
            proxyObject(this, key, val, true);
            let ob = this.$Observer;
            ob.observe(val);
            ob.convert(key, val);    
        }    
    });

    到此,一个简单的$set方法构建完毕。

    在上面我们提到,之所以需要一个恒定extendObj对象,是为了更好的代码管理。且,到目前为止,需要监听的对象上并没有扩展$set方法呢,所以,下面的事情就是为了达到以上效果,如下:

    //observer.js
    function Observer(data){
        if(!(this instanceof Observer)){
            return new Observer(data);
        }
        //将监听对象的隐指针指向我们的extendObj对象
        data.__proto__ = extendObj;
        this.data = data;
        this.walk(data);    
    }

    好了,一切完毕,接下来就测试下吧:

    <script src="./extendObj.js"></script>
    <script src="./observer.js"></script>
    <script>
        let data = {
            user: {
                name: 'Monkey',
                age: 24
            },
            lover: {
                name: 'Dorie',
                age: 23
            }
        };
        Observer(data);
    </script>

    效果如下:

    Perfect,完整代码见github 

  • 相关阅读:
    【2014 Multi-University Training Contest 3 1002】/【HDU 4888】 Redraw Beautiful Drawings
    8 shell命令之find
    [网络]_[0基础]_[使用putty备份远程数据]
    Cstyle的UEFI导读:第20.0篇 IGD OpRegion interface &amp;&amp; IGD OpRegion PROTOCOL
    Mac下使用MySQL
    Qt中截图功能的实现
    gdb经常使用命令总结
    Graphical Shell with WebShell
    SSH WebShell: SSH在线WEB管理器安装教程
    python—webshell_醉清风xf_新浪博客
  • 原文地址:https://www.cnblogs.com/giggle/p/6262157.html
Copyright © 2011-2022 走看看