JavaScript修改对象原型来监控变化

JavaScript Modify Object Prototype to Monitor Changes

本文关键字:监控 变化 原型 修改 对象 JavaScript      更新时间:2023-09-26

我正在尝试修改Object原型,以允许使用字符串比较监视整个对象(而不仅仅是Object.watch的属性)的变化。下面是我到目前为止所做的,只要我在每次修改后调用myobj.change(...),它就可以工作。

我希望完成的是一种方法来"重新绑定".change()对象,每次它被修改,所以我可以设置一个单一的变化处理程序,响应每当对象被操纵。

if (!Object.prototype.change) {
    Object.defineProperty(Object.prototype, "change", {
        value: function(handler) {
            var curVal = JSON.stringify(this);
            console.log('CUR:',curVal);
            console.log('STATE:', this.__proto__.state);
            if (curVal!==this.__proto__.state) {
                this.__proto__.state = JSON.stringify(this);
                handler.call(this);
            }
        }
    });
}
var myobj = { foo: 'bar' };
myobj.change(function(){
    console.log('Changed!');
});
myobj = { foo: 'qux' };
myobj.change(function(){
    console.log('Changed!');
});
myobj = { foo: 'sit' };
myobj.change(function(){
    console.log('Changed!');
});

小提琴在这里:http://jsfiddle.net/fluidbyte/GE9t3/

WatchAll对象

下面是一些快速而粗糙的代码,用于监视对象上定义的任何属性的更改。它要求初始化一个特定类型的新对象,WatchAll

代码
var WatchAll = function (properties, change_handlers) {
  var obj = Object.create(null);
  var key;
  var i;
  for (key in properties) {
    obj[key] = null;
    Object.defineProperty(this, key, {
      enumerable: true,
      configurable: true,
      get: function () {
        return obj[key];
      },
      set: function (new_value) {
        var old_value = obj[key];
        obj[key] = new_value;
        // notify the change handlers
        for (i = 0; i < change_handlers.length; i++) {
          change_handlers[i](key, old_value, new_value);
        }
      }
    });
    this[key] = properties[key];
  }
};
function logUpdatedProperty (key, old_value, new_value) {
  console.log(key + ' was changed from ' + old_value + ' to ' + new_value);
}
var myobj = new WatchAll({ foo: 'bar', testing: 123 }, [logUpdatedProperty]);
myobj.foo = 'qux';   // from bar to qux
myobj.foo = 'sit';   // from qux to sit
myobj.testing = 456; // from 123 to 456
myobj.foo = 'bar';   // from sit to bar
myobj.testing = 123; // from 456 to test

JavaScript版本/浏览器兼容性

我用NodeJS测试了代码,但它应该在任何浏览器中工作(当然除了IE8和IE7)。下面是Object.defineProperty的浏览器兼容性表。

用WatchAll包裹现有对象

要包装现有对象,只需枚举它们的属性,并使用正确的更改处理程序将它们的值复制到新的WatchAll对象:

function wrapWithWatchAll (obj, change_handlers) {
  var propagateChangeBackToOriginalObject = function (key, old_value, new_value) {
    obj[key] = new_value;
  };
  return new WatchAll(obj, [propagateChangeBackToOriginalObject].concat(change_handlers));
}
var existingobj = { name: 'omouse', skills: 'programming' };
var wrappedobj = wrapWithWatchAll(existingobj, [logUpdatedProperty]);
wrappedobj.name = 'rudolf';                   // from omouse to rudolf
wrappedobj.skills = 'javascript';             // from programming to javascript
console.log('wrapped: ' + wrappedobj.name);   // rudolf
console.log('existing: ' + existingobj.name); // rudolf

这里的问题是,您将不得不在任何地方使用已包装的对象,因此您必须将现有对象与已包装的对象交换。