• 模拟Vue之数据驱动2


    一、前言

    在随笔“模拟Vue之数据驱动1”结尾处,我们说到如果监听的属性是个对象呢?那么这个对象中的其他属性岂不就是监听不了了吗?

    如下:

     

    倘若user中的name、age属性变化,如何知道它们变化了呢?

    今儿,就来解决这一问题。

    通过走读Vue源码,发现他是利用Observer构造函数为每个对象创建一个Observer对象,来监听数据的,如果数据中的属性又是一个对象,那么就又通过Observer来监听嘛。

    其实,核心思想就是树的先序遍历(关于树,可参考here)。如我们将上述Demo中的data数据,图形化一下,就更加明白了,如下:

     

    好了,理清了大体思路,下面我们就一起来创建一个Observer吧。

    二、Observer构造

    Observer整体结构如下:

    function Observer(data){
        //如若this不是Observer对象,即创建一个
        if(!(this instanceof Observer)){
            return new Observer(data);
        }
        this.data = data;
        this.walk(data);    
    }
    
    let p = Observer.prototype = Object.create(null);
    
    p.walk = function(data){
        /*
        TODO:监听data数据中的所有属性,
        并查看data中属性值是否为对象,
        若为对象,就创建一个Observer实例
        */    
    }
    
    p.convert = function(key, val){
        //TODO:通过Object.defineProperty监听数据    
    }

    好了,下面,我们一起来完成walk以及convert方法吧。

    -walk-

    首先,我们在walk方法中实现对data对象中的所有属性监听,如下:

    p.walk = function(data){
        let keys = Object.keys(data);
        keys.forEach( key => {
            let val = data[key];
            this.convert(key, val);
        });
    }

    且,由于属性中可能又会是一个对象,那么,我们就有必要监听它们。

    怎么办呢?

    如果是个对象,再次利用Observer构造函数,处理它不就完了么。

    如下:

    p.walk = function(data){
        let keys = Object.keys(data);
        keys.forEach( key => {
            let val = data[key];
            //如果val为对象,则交给Observer处理
            if(typeof val === 'object'){
                Observer(val);
            }
            this.convert(key, val);
        });
    }

    你可能会有这样的疑问,如果直接利用Observer处理对象,那么不就与父对象失去关联了么?

    然而并没有,因为JavaScript对于对象是指向地址关系,所以怎么会失去关联呢。

    -convert-

    对于convert方法,就比较简单了,一如既往就是利用Object.defineProperty监听数据,如下: 

    p.convert = function(key, val){
        Object.defineProperty(this.data, key, {
            get: ()=>{
                console.log('访问了'+key+'  值为'+val);
                return val;
            },
            set: (newVal)=>{
                console.log('设置了'+key+'  值为'+newVal);
                if(newVal !== val){
                    val = newVal;
                }
            }
        });
    }

    好了,到此,一个简单的Observer就构造完成,下面我们就来测试下,是否成功监听了每个属性。

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

    效果如下:

    Perfect,完整代码见github 

  • 相关阅读:
    解决centos7的root账户下无法通过code命令启动vscode
    centos7安装epel
    centos7用过yum安装vscode
    yum install gcc报错Error: Package: glibc-2.17-260.el7_6.6.i686 (updates) Requires: glibc-common = 2.17
    centos7通过yum从vim7升级到vim8
    解决VM虚拟机安装centos7无法联网
    centos7设置开机默认使用root账户登陆
    centos7使用sudo命令提示sudo command not found
    不同编译器下C++基本数据类型的字节长度
    C++函数模板
  • 原文地址:https://www.cnblogs.com/giggle/p/6261973.html
Copyright © 2020-2023  润新知