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

    一、前言

    在"模拟Vue之数据驱动3"中,我们实现了为每个对象扩展一个$set方法,用于新增属性使用,这样就可以监听新增的属性了。

    当然,数组也是对象,也可以通过$set方法实现新增属性。

    但是,对于数组而言,通常我们是通过push之类的方法吧。

    PS:Vue中明确指出push、pop、shift、unshift、splice、sort、reverse方法为变异方法,可以通过它们监听属性变化,触发视图更新(详情见here

    下面,我们就一起来实现这些Array的变异方法吧。

    注:我们将Array变异方法实现,也写在extendObj.js中的,因为数组也是对象嘛。

    二、Array变异方法实现

    要实现这些变异方法,毫无疑问,我们会重写它们,那在Array.prototype里面重写吗?

    当然不是,这样不就影响了所有数组对象的原型链了么!

    为了避免这种情况,且,我们只是想在监听数据对象上继承这些变异数组方法,那么细心的你会发现,其实与我们在"模拟Vue之数据驱动3"中实现$set方法类似了。

    首先,我们创建arrKeys对象用于保存需要变异的数组方法以及恒定对象extendArr,如下:

    let arrKeys = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];
    const extendArr = [];

    接着,就是在extendArr对象上,一一监听arrKeys中的方法了,与$set方法类似,整体结构如下:

    !function(){
        arrKeys.forEach(function(key){
            proxyObject(extendArr, key, function(){
                //TODO
            });
        });
    }();

    注:proxyObject方法其实核心就是Object.defineProperty,详见"模拟Vue之数据驱动3".

    接下来,就是实现核心部分代码了,重写这些方法的目的,是为了监听数据变化,所以要在方法原有功能不变的情况下,重写它们,Array.xxx.apply即可实现原有功能。

    且,push、unshift、splice这三个方法可以在原数组中,新增属性,故而,我们需要监听新增属性以及它们的属性值,这里就和$set方法完全一样了,通过$Observer,即可利用observe以及convert方法实现了。

    实现代码如下: 

    !function(){
        arrKeys.forEach(function(key){
            proxyObject(extendArr, key, function(){
                console.log('Fun ' + key + ' is observed');
                let result;
                let arrProto = Array.prototype;
                let ob = this.$Observer;
                let arr = arrProto.slice.call(arguments);
                let inserted;
                let index;
                switch(key){
                    case 'push': {
                        inserted = arr;
                        index = this.length;
                        break;
                    }
                    case 'unshift': {
                        inserted = arr;
                        index = 0;
                        break;
                    }
                    case 'splice': {
                        inserted = arr.slice(2);
                        index = arr[0];
                        break;
                    }
                }
                result = arrProto[key].apply(this, arguments);
                if(inserted){
                    inserted.forEach(val => {
                        ob.observe(val);
                        ob.convert(index++, val);
                    });
                }
                return result;
            });
        });
    }();
    代码稍长,请自行打开

    最后,就是在需要监听的对象上继承这些变异方法咯,如下:

    //observer.js
    function Observer(data){
        if(!(this instanceof Observer)){
            return new Observer(data);
        }
        data.__proto__ = extendObj;
        //继承变异方法push、pop等等
        if(Array.isArray(data)){
            data.__proto__.__proto__ = extendArr;
        }
        this.data = data;
        this.walk(data);    
    }

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

    <script src="./extendObj.js"></script>
    <script src="./observer.js"></script>
    <script>
        'use strict';
        let data = {
            msg: [5, 2, 0],
            user: {
                name: 'Monkey',
                age: 24
            },
            lover: {
                name: 'Dorie',
                age: 23
            }
        };
        Observer(data);
    </script>

    效果如下:

    Perfect,此时,你可能会想,数组方法中仅有push、unshift、splice会为数组新增属性,那么我们又何必将其他方法,例如sort、reverse重写呢,也没发现有什么猫腻呢?

    不错,在此时,并没有什么卵用,但是,你要知道sort、reverse等这些方法,可是会引起数组变化的,那么就会影响视图展现,这些变化,又怎么通知数组呢?就是下篇随笔会具体说明的。

    该篇随笔代码,详情见github.

  • 相关阅读:
    WINCE基于CH7024实现TV OUT (VGA)功能
    Hello China操作系统在Virtual PC上的安装和使用
    内心独白之程序员思维
    物联网操作系统的架构和基本功能
    说不懂Android系统构架,太亏了!
    Hello China V1.75版本运行截图
    剥开ios 系统sandbox神秘面纱
    Android基础之广播
    《大象Thinking in UML 第二版》已于近日在当当首发,同时邀请各位加入新浪微博[大象thinkinginUml群]:http://q.weibo.com/1483929
    物联网操作系统随笔
  • 原文地址:https://www.cnblogs.com/giggle/p/6263232.html
Copyright © 2011-2022 走看看