【问题标题】:JavaScript Modify Object Prototype to Monitor ChangesJavaScript 修改对象原型以监控变化
【发布时间】:2013-04-20 16:34:36
【问题描述】:

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

【问题讨论】:

  • 您的问题有点令人困惑,因为如果不监视对象属性的更改,什么是“监视整个对象的更改”?您是否希望监控对所有属性的更改?

标签: javascript object prototype


【解决方案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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-24
    • 2022-01-07
    • 2011-10-05
    • 1970-01-01
    相关资源
    最近更新 更多