我正在尝试修改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!');
});
答案 0 :(得分:1)
这里有一些快速而脏的代码,用于监视对象上定义的任何属性的更改。它要求您初始化某种类型的新对象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
我用NodeJS测试了代码,但它应该适用于任何浏览器(当然除了IE8和IE7)。 Here's the browser compatibility table for Object.defineProperty
要包装现有对象,您只需枚举其属性并使用正确的更改处理程序将其值复制到新的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
这里的问题是你将不得不在任何地方使用包装对象,因此你必须将现有对象与包装对象交换。