vueの配列リスニング

21086 ワード

Vueでのデータの傍受は主にObject.definePropertyによって実現され、このような実現は主にkey/value形式のオブジェクトに対して、配列中の値の変化に対して無力であり、definrPropertyは配列長の変化を傍受することができず、傍受インデックスの代価も高い.では、どのように配列中のデータを傍受すべきか.
一、配列の変化状況:
  • 配列自体の付与
  • 配列におけるpush等の方法による変化
  • 配列における値変化
  • 動作配列の長さによる変化
  • 二、上の変化を順次分析する.
    配列自体の割り当て
    この場合,オブジェクトの傍受と一致し,definePropertyを直接用いてデータを傍受すればよい.
    配列におけるpushなどの方法による変化
    配列push等の操作によりデータが変更された場合に傍受したいデータの変化はdefinePropertyでは実現できない.どうやって実現するの?
  • は、Object.createによってArray.prototypeの後継者arraymethodsを実現する必要がある.アクセス方法とArray.prototypeは同じです.私たちは直接Arrayにいることはできません.prototypeでは、通常のメソッドの呼び出しに影響を与えるため、メソッドをリスニングします.
  • pushなどの方法は、definepropertyを介してarraymethodsオブジェクトに直接書き込む:
  • .
    const methodsToPatch = [
        'push',
        'pop',
        'shift',
        'unshift',
        'splice',
        'reverse',
        'sort'
    ];
    const arrayProto = Array.prototype, //  Array   
    arrayMethods = Object.create(arrayProto); //  Array   
    //           
    function def(obj, key, val) {
        Object.defineProperty(obj, key, {
            value: val,
            enumerable: true,
            writable: true,
            configurable: true
        });
    }
    methodsToPatch.forEach(function(method, index) {
        def(arrayMethods, method, function(...args) {
            //arrayProto[method].apply(this, args);       
        });
    });
    
  • このとき、arraymethodsの7つのメソッドに直接アクセスすると、arraymethodsのオブジェクトに直接アクセスし、内部にarrayProto[method].apply(this,args)を介して配列上の本当のメソッドにアクセスするリスニングが必要なメソッドを書くことができます.
  • arraymethodsは私たちが構築した構造であり、それ自体が配列ではないので、私たちが操作している配列に対して、本当のarraymethodsの方法ではなく、Array.prototypeの方法を指すようにします.
  • if('__proto__' in {}) {
        //     __proto__,        arrayMethods,          7    ,     arrayMethods         Array.prototype    
        target.__proto__ = arrayMethods;
    } else {
        //        __proto__,     arraymethods            。          ,          7    ,                
        for(let i = 0, l = methodsToPatch.length; i < l; i++) {
            let key = methodsToPatch[i];
            def(target, key, arrayMethods[key]);
        }
    }
    

    完全なコード:
    const patchArray = (function() {
    const methodsToPatch = [
        'push',
        'pop',
         'shift',
        'unshift',
        'splice',
        'reverse',
        'sort'
    ];
    //           
    function def(obj, key, val) {
        Object.defineProperty(obj, key, {
            value: val,
            enumerable: true,
            writable: true,
            configurable: true
        });
    }
    const arrayProto = Array.prototype, //  Array   
    arrayMethods = Object.create(arrayProto); //  Array   
        methodsToPatch.forEach(function(method, index) {
            def(arrayMethods, method, function(...args) {
                //    Array     
                const old=this.concat([]);
                const res = arrayProto[method].apply(this, args);
                let inserted = null,
                deleted = null;
                let _callback_ = this._callback_;
                //      
                switch(method) {
                    case 'push':
                    case 'unshift':
                        inserted = args;
                    break;
                    case 'splice':
                    //     
                        inserted = args.slice(2);
                        let start = args[0],
                        end = start + args[1];
                        deleted = old.slice(start, end);
                    break;
                    case 'pop':
                    case 'shift':
                    deleted = res;
                }
                _callback_(inserted, deleted);
                return res;
            });
    });
    return function(target, callback) {
        def(target, '_callback_', callback); //    
            //         __proto__    ,    __proto__  ,         
            if('__proto__' in {}) {
                //        arrayMethods,          7    ,     arrayMethods         Array.prototype    
                target.__proto__ = arrayMethods;
            } else {
                //        __proto__,          ,          7    ,                
                for(let i = 0, l = methodsToPatch.length; i < l; i++) {
                    let key = methodsToPatch[i];
                    def(target, key, arrayMethods[key]);
                }
            }
        }
    })();
    //  
    let arr = [1, 2, 3];
    patchArray(arr, function(add, del) {
    if(add)
        console.log('       :', add);
    if(del)
        console.log('       :', del);
    });
    arr.splice(1,2,'aa','bb','cc')
    

    参照ドキュメント:http://www.qiutianaimeili.com/html/page/2019/05/m0kcbzlpc9s.html https://www.cnblogs.com/DevinnZ/p/10569033.html