I'm trying to find similar functionality to AngularJS's $watch function (as defined here) which allows for 'watching of complex objects' and their changes. To the best of my knowledge, I understand it as being able to watch changes to variables within the object even if they themselves are also within an object (within the object being watched).
I wish to have this same 'watchability' in native JavaScript (or JQuery) but I can't seem to find anything. I know of Object.watch() and the Polyfill as found here but I'm pretty certain this only does reference checking or only watches the 'immediate' variables within the object and not anything that is nested so to speak and does not check properties 'deep' inside the object.
Does anyone know of any library, functions, anything that could help me to provide this 'deep watching' capability? Or even help me to understand Object.watch() a bit better if it does in-fact provide what I'm wanting?
I am creating a real-time music application and want to have a 'deep' watch on the instrument so I can see if any of its variables, parameters, etc.. change so I can sync it to the server and other clients.
Any help would be greatly appreciated, thanks!
As @Booster2ooo mention you can use Proxy object to observe the changes, you can use something like this:
function proxify(object, change) {
// we use unique field to determine if object is proxy
// we can't test this otherwise because typeof and
// instanceof is used on original object
if (object && object.__proxy__) {
return object;
}
var proxy = new Proxy(object, {
get: function(object, name) {
if (name == '__proxy__') {
return true;
}
return object[name];
},
set: function(object, name, value) {
var old = object[name];
if (value && typeof value == 'object') {
// new object need to be proxified as well
value = proxify(value, change);
}
object[name] = value;
change(object, name, old, value);
}
});
for (var prop in object) {
if (object.hasOwnProperty(prop) && object[prop] &&
typeof object[prop] == 'object') {
// proxify all child objects
object[prop] = proxify(object[prop], change);
}
}
return proxy;
}
and you can use this fuction like this:
object = proxify(object, function(object, property, oldValue, newValue) {
console.log('property ' + property + ' changed from ' + oldValue +
' to ' + newValue);
});
...
You shouldn't use Object.watch
Warning: Generally you should avoid using watch() and unwatch() when possible. These two methods are implemented only in Gecko, and they're intended primarily for debugging use. In addition, using watchpoints has a serious negative impact on performance, which is especially true when used on global objects, such as window. You can usually use setters and getters or proxies instead. See Browser compatibility for details. Also, do not confuse Object.watch with Object.observe.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch
I'd rather have a look at Proxies:
The Proxy object is used to define custom behavior for fundamental operations (e.g. property lookup, assignment, enumeration, function invocation, etc).
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
And maybe MutationObserver if the DOM in implied:
MutationObserver provides developers with a way to react to changes in a DOM. It is designed as a replacement for Mutation Events defined in the DOM3 Events specification.
https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
Explore & enjoy :)
jcubic's answer is solid, but unfortunately it will not work with nested objects.
I published a library on GitHub (Observable Slim) that will allow you to observe/watch for changes that occur to a object and any nested children of that object. It also has a few extra features:
It works like this:
var test = {testing:{}};
var p = ObservableSlim.create(test, true, function(changes) {
console.log(JSON.stringify(changes));
});
p.testing.blah = 42; // console: [{"type":"add","target":{"blah":42},"property":"blah","newValue":42,"currentPath":"testing.blah",jsonPointer:"/testing/blah","proxy":{"blah":42}}]
Please feel free to take a look and hopefully contribute as well!