Data detection of mvvm (notes)

// Code source: https://github.com/HcySunYang/jsonob/blob/master/src/index.js
// The optimization steps and questions are as follows:
1: bug->The assignment expression and the value in the set method in the observe function The listening expressions are written in the wrong order
2: Optimization -> overrideArrayProto function, no result return value (fakeProperty does not need return value)
3: Question -> Outputting the array, the result is not an array, but'( [ Getter/Setter], [Getter/Setter], [Getter/Setter]]', why is this?
4: Question -> In line 67, isn't this just oldArray? Why use this.slice(0) for assignment, Instead of using this directly?

After contacting the author of hcy, I responded immediately, thank you very much! The reply is as follows:
For the third question, it is because the elements of the array are set as accessor attributes, but all accessor attributes are printed out get/set format. Don't worry about the fourth question, you can check http://hcysun.me/vue-design/art/7vue-reactive.html. There is a complete vue implementation

function log(){
    var args = Array.prototype.slice.call(arguments);
    console.log.apply(console, args);
}

function isObject(obj){
    return Object.prototype.toString.call(obj) === '[object Object]'
}

function isArray(arr){
    return Object.prototype.toString.call(arr) === '[object Array]'
}

const OAM = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];

class JsonOBJ {
    constructor(obj, callback){
        if(!isObject(obj) && !isArray(arr)){ //数组也可以侦听
            throw new Error('the parameter obj show be object or array!')
        }
        this.$callback = callback;
        this.observe(obj)
    }

    observe(obj, pathArr){
        if(isArray(obj)){
            this.overrideArrayProto(obj, pathArr)
        }

        Object.keys(obj).forEach(ObjKey => {//改为es6语法
        //对patharr逻辑进行优化
            var tempPathArr = pathArr && pathArr.slice(0) || [];
            tempPathArr.push(ObjKey);

            const oldVal = obj[ObjKey];

            Object.defineProperty(obj, ObjKey, {
                get: function(){
                    return oldVal;
                },
                set:(function(newVal){
                    if(oldVal !== newVal){
                        this.$callback(newVal, oldVal, tempPathArr)
			
			//源代码这里是错误的,应该先赋值,再侦听
                        oldVal = newVal;
                        this.observe(oldVal, tempPathArr);
                    }
                }).bind(this)
            })

            if(isArray(oldVal) || isObject(oldVal)){
                this.observe(oldVal, tempPathArr);
            }
        })
    }

    overrideArrayProto(arr, pathArr){
        const originProto = Array.prototype;
        const overrideProto = Object.create(originProto);
        const self = this;
       //let result://这里不需要result,因为value函数不需要返回值

        OAM.forEach(method => {
            Object.defineProperty(overrideProto, method, {
                value:function(){
                    const oldVal = this.slice(0);

                    var arg = [].slice.apply(arguments);
                    originProto[method].apply(this, arg);

                    self.observe(this, pathArr);
                    self.$callback(this, oldVal, pathArr)
                },
                writable:true,
                configurable:true,
                enumerable:false
            })
        })

        arr.__proto__ = overrideProto;
    }
}


var data = {
    a: 200,
    level1: {
        b: 'str',
        c: [[1,2], 2, 3],
        level2: {
            d: 90
        }
    }
}

new JsonOBJ(data, log)
// data.level1.b = 'sss';
// data.level1.level2.d = 'msn';
data.level1.c[0].push([5,6]);

Guess you like

Origin blog.csdn.net/a519991963/article/details/84309722