-
Star
(828)
You must be signed in to star a gist -
Fork
(195)
You must be signed in to fork a gist
-
-
Save eligrey/384583 to your computer and use it in GitHub Desktop.
/* | |
* object.watch polyfill | |
* | |
* 2012-04-03 | |
* | |
* By Eli Grey, http://eligrey.com | |
* Public Domain. | |
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK. | |
*/ | |
// object.watch | |
if (!Object.prototype.watch) { | |
Object.defineProperty(Object.prototype, "watch", { | |
enumerable: false | |
, configurable: true | |
, writable: false | |
, value: function (prop, handler) { | |
var | |
oldval = this[prop] | |
, newval = oldval | |
, getter = function () { | |
return newval; | |
} | |
, setter = function (val) { | |
oldval = newval; | |
return newval = handler.call(this, prop, oldval, val); | |
} | |
; | |
if (delete this[prop]) { // can't watch constants | |
Object.defineProperty(this, prop, { | |
get: getter | |
, set: setter | |
, enumerable: true | |
, configurable: true | |
}); | |
} | |
} | |
}); | |
} | |
// object.unwatch | |
if (!Object.prototype.unwatch) { | |
Object.defineProperty(Object.prototype, "unwatch", { | |
enumerable: false | |
, configurable: true | |
, writable: false | |
, value: function (prop) { | |
var val = this[prop]; | |
delete this[prop]; // remove accessors | |
this[prop] = val; | |
} | |
}); | |
} |
@rokobuljan That's not an issue... You're not returning the desired new value in the watch.
var myObject = {test:"a"};
myObject .watch("test", function (id, oldval, newval) {
console.log(oldval+' '+ newval);
return newval;
});
myObject .test = "b"; // "a b"
myObject .test = "c"; // "b c"
Hey man! I made an awesome popup blocker with your snippet. https://gist.github.com/MMDF/d793c6dced90a41495a1dd61d6bf2f5b
Take a look and add it to Tampermonkey to use it. Thanks for the public snippet!
This was a day saver. Thanks for your nice snippet :)
A more generic version is possible. Instead of getting directly this[prop] at the start, the watch function should try to getOwnPropertyDescriptor on the object or along its prototype chain until it succeeds, then handle accessor properties by invoking the original getter/setter. This way you can watch html input elements "value" and "checked" properties for programmatic modification for example.
Has anyone developed a version that would track children properties too?
@mateuszgwozdz Vue.js can do it.
@georgir What are you referring to, exactly? Can you provide an example?
Is it possible to watch window and check when variable is set with var el
?
value: function( prop, handler ){
var oldval = this[prop],
getter = () => ( oldval ),
setter = function( val ){
if ( oldval != val ){ // event with a different value
handler.call( this, prop, oldval, val);
return ( oldval = val );
}
};
@stefek99 : the handler function must return the new value
alternatively, if you want a behavior more akin watchers in vue/react/angular you can modify the setter function as follows:
setter = function (val) {
oldval = newval;
return newval = (function() {
handler.call(this, prop, oldval, val);
return val;
})();
};
if forces the new value to always be passed and assigned to the property, and the handler function becomes just "notified" of the change
Seems there's an issue
undefined
on the oldvalfiddle demo
var myObject = {test:"a"};
myObject .watch("test", function (id, oldval, newval) {
console.log(oldval+' '+ newval);
});
myObject .test = "b"; // "a b"
myObject .test = "c"; // "undefined c"