-
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; | |
} | |
}); | |
} |
simple delete prop make it looks like not so perfect, if somewhere have call Object.defineProperty(target, targetProto) before watch , so the setter and getter (if exist) can't work
take a look at my modification, sorry for that i have not test it yet
https://gist.github.com/xsilen/e301dd675d27f3fa036a
and also sorry for unwatch implement
Excellent!
Thanks for this one.
Seems there's an issue undefined
on the oldval
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"
@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
http://jsfiddle.net/webarthur/dykobdxk/
=D