在JS中如何检测对象的改变?

Posted by 启示录 Blog on December 28, 2018

有时候在业务当中会遇到当某个对象改变的时候做一些逻辑处理。在Vue里面数据的双向绑定则是也提到监控对象的变化。主要是利用Object.defineProperty特性。下面是一段对Object.defineProperty扩展实现对象的监控。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
//https://gist.github.com/eligrey/384583
// object.watch
if (!Object.prototype.watch) {
    //在所有对象定义一个watch熟悉,设置为不可重写
    Object.defineProperty(Object.prototype, "watch", {
        //当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中。
          enumerable: false
        //当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除
        , configurable: true 
        //当且仅当该属性的writable为true时,value才能被赋值运算符改变。
        , writable: false
        //该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。
        , value: function (prop, handler) {
        //watch属性的值是一个函数。参数为对象的key和回调
            var
              oldval = this[prop]
            , newval = oldval
            //读取时直接返回
            , getter = function () {
                return newval;
            }
            //修改时执行回调,回调的参数是key,旧值,新值
            , setter = function (val) {
                oldval = newval;
                return newval = handler.call(this, prop, oldval, val);
            }
            ;
            // can't watch constants
            if (delete this[prop]) { 
                Object.defineProperty(this, prop, {
                    //一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。
                      get: getter
                    //修改时执行
                    , set: setter
                    , enumerable: true
                    , configurable: true
                });
            }
        }
    });
}

// object.unwatch,解除绑定
if (!Object.prototype.unwatch) {
    Object.defineProperty(Object.prototype, "unwatch", {
          enumerable: false
        , configurable: true
        , writable: false
        , value: function (prop) {
            var val = this[prop];
            delete this[prop]; // remove accessors
            this[prop] = val;
        }
    });
}
//example
let a = {test:1};    
a.watch('test',function(){
    console.log('change')
});
a.test = 3;
a.unwatch('test');
a.test = 2;

有一个开发者基于上面的思想实现了一个库,可以在多种环境下面使用。Watch.JS

参考资料