返回博主主页

js监听数据的变化。

原生js实现检测对象变化。

通过把属性转换为访问器属性,实现监听。

对象属性的更改通过设置 get, set。

数组类型元素的更改通过在prototype重载操作数据的方法:slice、push、shift……

const OP = Object.prototype;
const types = {
    obj: '[object Object]',
    array: '[object Array]'
}
const OAM = ['push', 'pop', 'shift', 'unshift', 'short', 'reverse', 'splice']
class Jsonob {
    constructor(obj, cb) {
        if (OP.toString.call(obj) !== types.obj && OP.toString.call(obj) !== types.array) {
            console.log('请传入一个对象或数组');
            return false;
        }
        this._callback = cb;
        this.observe(obj);
    }
    observe(obj, path) {
        if (OP.toString.call(obj) === types.array) {
            this.overrideArrayProto(obj, path);
        }
        Object.keys(obj).forEach((key)=>{
            let oldVal = obj[key];
            let pathArray = path && path.slice();
            if (pathArray) {
                pathArray.push(key);
            } else {
                pathArray = [key];
            }
            Object.defineProperty(obj, key, {
                get: function() {
                    return oldVal;
                },
                set: (function(newVal) {
                    if (oldVal !== newVal) {
                        if (OP.toString.call(newVal) === '[object Object]') {
                            this.observe(newVal, pathArray);
                        }
                        this._callback(newVal, oldVal, pathArray)
                        oldVal = newVal
                    }
                }
                ).bind(this)
            })
            if (OP.toString.call(obj[key]) === types.obj || OP.toString.call(obj[key]) === types.array) {
                this.observe(obj[key], pathArray)
            }
        }
        , this)
    }
    overrideArrayProto(array, path) {
        // 保存原始 Array 原型  
        var originalProto = Array.prototype, // 通过 Object.create 方法创建一个对象,该对象的原型是Array.prototype  
        overrideProto = Object.create(Array.prototype), self = this, result;
        // 遍历要重写的数组方法  
        OAM.forEach((method)=>{
            Object.defineProperty(overrideProto, method, {
                value: function() {
                    var oldVal = this.slice();
                    //调用原始原型上的方法  
                    result = originalProto[method].apply(this, arguments);
                    //继续监听新数组  
                    self.observe(this, path);
                    self._callback(this, oldVal, path);
                    return result;
                }
            })
        }
        );
        // 最后 让该数组实例的 __proto__ 属性指向 假的原型 overrideProto  
        array.__proto__ = overrideProto;

    }
}
var data = {
    a: 200,
    level1: {
        b: 'str',
        c: [1, 2, 3],
        level2: {
            d: 90
        }
    }
}
var cb = (...val)=>{
    console.log("calllback", ...val)
}
var rreess = new Jsonob(data,cb);
data.level1.level2.d = 50
data.a = 998
data.level1.c.unshift(0)

 

posted @ 2022-02-12 18:01  懒惰的星期六  阅读(6644)  评论(0编辑  收藏  举报

Welcome to here

主页