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)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM