JavaScript修改对象原型以监视更改

时间:2013-04-20 16:34:37

标签: javascript object prototype

我正在尝试修改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/

1 个答案:

答案 0 :(得分:1)

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)。 Here's the browser compatibility table for 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

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