3

我正在尝试修改原型,以允许使用字符串比较Object监视整个对象(而不仅仅是像 with 之类的属性)的更改。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/

4

1 回答 1

2

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

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

于 2014-08-05T08:04:34.697 回答