Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
object.watch polyfill in ES5
/*
* 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;
}
});
}
@Swivelgames
Copy link

Swivelgames commented Nov 16, 2016

@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"

@MMDF
Copy link

MMDF commented Jan 31, 2017

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!

@alierdogan7
Copy link

alierdogan7 commented Apr 9, 2017

This was a day saver. Thanks for your nice snippet :)

@georgir
Copy link

georgir commented May 15, 2017

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.

@mategvo
Copy link

mategvo commented Jul 28, 2017

Has anyone developed a version that would track children properties too?

@Erutan409
Copy link

Erutan409 commented Mar 9, 2018

@mateuszgwozdz Vue.js can do it.

@Erutan409
Copy link

Erutan409 commented Mar 9, 2018

@georgir What are you referring to, exactly? Can you provide an example?

@chack1172
Copy link

chack1172 commented Apr 18, 2018

Is it possible to watch window and check when variable is set with var el?

@BSBProphet
Copy link

BSBProphet commented Dec 4, 2019

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 );
}
};

@rubenreyes2000
Copy link

rubenreyes2000 commented Apr 18, 2020

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment