Create a gist now

Instantly share code, notes, and snippets.

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

This comment has been minimized.

Show comment Hide comment
@Tobriand

Tobriand Aug 10, 2011

Thanks for this snippet! It's way beyond my level of JS and incredibly useful.

I did have to modify it somewhat - the setter function is broken if the handler function doesn't return the new value. Took me a while, but I figured out how to fix it!

Thanks for this snippet! It's way beyond my level of JS and incredibly useful.

I did have to modify it somewhat - the setter function is broken if the handler function doesn't return the new value. Took me a while, but I figured out how to fix it!

@johndkane

This comment has been minimized.

Show comment Hide comment
@johndkane

johndkane Aug 30, 2011

Tobriand, are you able to contribute the fix that you said you made, to the author for review and possible inclusion in the script. That could be helpful to others.

Tobriand, are you able to contribute the fix that you said you made, to the author for review and possible inclusion in the script. That could be helpful to others.

@BigBlueHat

This comment has been minimized.

Show comment Hide comment
@BigBlueHat

BigBlueHat Oct 11, 2011

Thanks for building this. What license is it released under? (no license === All Rights Reserved...at least in the US). Thanks.

Thanks for building this. What license is it released under? (no license === All Rights Reserved...at least in the US). Thanks.

@eligrey

This comment has been minimized.

Show comment Hide comment
@eligrey

eligrey Oct 11, 2011

MIT

Owner

eligrey commented Oct 11, 2011

MIT

@BigBlueHat

This comment has been minimized.

Show comment Hide comment
@BigBlueHat

BigBlueHat Oct 11, 2011

Cool. Would you mind adding the MIT header? http://en.wikipedia.org/wiki/MIT_License#License_terms Sadly, that's the only way it really "counts." Thanks.

Cool. Would you mind adding the MIT header? http://en.wikipedia.org/wiki/MIT_License#License_terms Sadly, that's the only way it really "counts." Thanks.

@eligrey

This comment has been minimized.

Show comment Hide comment
@eligrey

eligrey Oct 11, 2011

I'd have a hard time in court proving that I didn't put this under the MIT license after the comment I just explicitly made.

Owner

eligrey commented Oct 11, 2011

I'd have a hard time in court proving that I didn't put this under the MIT license after the comment I just explicitly made.

@BigBlueHat

This comment has been minimized.

Show comment Hide comment
@BigBlueHat

BigBlueHat Oct 12, 2011

I completely understand and agree. :) However, "corporate types" generally steer clear of any code that doesn't include both a copyright and a licensing claim (even if it's just "@license MIT" or some such). I'll likely use this in my own projects, regardless. :) Thanks for the license change. Making it more explicit may get it more usage, but that's completely your call.

In any case, I appreciate you licensing it and discussing this with me. Thanks, Eli.

I completely understand and agree. :) However, "corporate types" generally steer clear of any code that doesn't include both a copyright and a licensing claim (even if it's just "@license MIT" or some such). I'll likely use this in my own projects, regardless. :) Thanks for the license change. Making it more explicit may get it more usage, but that's completely your call.

In any case, I appreciate you licensing it and discussing this with me. Thanks, Eli.

@ericcholis

This comment has been minimized.

Show comment Hide comment
@ericcholis

ericcholis Oct 26, 2011

There is a conflict with this script and Mootools that I can't seem to work out. I'm using MooTools Core 1.4.1 with MooTools More 1.4.01 (Specifically with Form.Request).

The error only happens in browsers that don't have native Object.watch(). Specifically, the error is:

Uncaught TypeError Object (... the watch() function above ...) has no method include.

Here's an example of the code that kicks an error:

window.addEvent('domready', function(){
  document.id('TestForm').formUpdate(null,{
    onComplete: function(target, tree, elements, html, javascript){
      console.log('Done!!')
    }
  });
});

The conflicting code is in MooTools Core, on the this.Events.addEvent() function; excerpt below:

 this.$events[type] = (this.$events[type] || []).include(fn);

I'm guessing that the 'watch' function you've created is conflicting with a MooTools internal "watch" function, event, or other reserved word.

Update
Seems that the culprit is a for in loop. Oddly enough, the object passed to that loop only has three members. However, the for loops through 5 members, the additional two being watch and unwatch. Example:

var events = {event1: function(),event2: function(), event3: function()};

console.log(events);

for (var fn in events) console.log(fn);

Modifying the Object.prototype screws with for in loops. In the case of mootools, I'll be using Object.extend('watch',function(){}); instead of adjusting the prototype.

Also, for the time being, I've only found that this conflicts with Events.Pseudos of MooTools More. I've added the following code as a hack to get it functioning:

Object.prototype.watch.extend('include',function(){return});

I've forked this for those that might want to use this with MooTools: https://gist.github.com/1319481

There is a conflict with this script and Mootools that I can't seem to work out. I'm using MooTools Core 1.4.1 with MooTools More 1.4.01 (Specifically with Form.Request).

The error only happens in browsers that don't have native Object.watch(). Specifically, the error is:

Uncaught TypeError Object (... the watch() function above ...) has no method include.

Here's an example of the code that kicks an error:

window.addEvent('domready', function(){
  document.id('TestForm').formUpdate(null,{
    onComplete: function(target, tree, elements, html, javascript){
      console.log('Done!!')
    }
  });
});

The conflicting code is in MooTools Core, on the this.Events.addEvent() function; excerpt below:

 this.$events[type] = (this.$events[type] || []).include(fn);

I'm guessing that the 'watch' function you've created is conflicting with a MooTools internal "watch" function, event, or other reserved word.

Update
Seems that the culprit is a for in loop. Oddly enough, the object passed to that loop only has three members. However, the for loops through 5 members, the additional two being watch and unwatch. Example:

var events = {event1: function(),event2: function(), event3: function()};

console.log(events);

for (var fn in events) console.log(fn);

Modifying the Object.prototype screws with for in loops. In the case of mootools, I'll be using Object.extend('watch',function(){}); instead of adjusting the prototype.

Also, for the time being, I've only found that this conflicts with Events.Pseudos of MooTools More. I've added the following code as a hack to get it functioning:

Object.prototype.watch.extend('include',function(){return});

I've forked this for those that might want to use this with MooTools: https://gist.github.com/1319481

@melanke

This comment has been minimized.

Show comment Hide comment
@melanke

melanke Jan 17, 2012

thank you so much, Ive made a fork that could be useful:
https://gist.github.com/1627705

take a look at the usage:

object.watchAll(function(){
alert("some attribute of object has been changed");
});

object.watchMany([
"attr1", "attr2"
],
function(){
alert("attribute attr1 or attr2 of object has been changed");
});

object.watchOne("attr1", function(){
alert("attribute attr1 of object has been changed");
});

object.attr1 = "different value"; //will trigger a object.attr1 watch or object watchAll
//WORKS WITH ARRAYS TOO!
object.attr1.push("new item"); //will trigger a object.attr1 watch or object watchAll

melanke commented Jan 17, 2012

thank you so much, Ive made a fork that could be useful:
https://gist.github.com/1627705

take a look at the usage:

object.watchAll(function(){
alert("some attribute of object has been changed");
});

object.watchMany([
"attr1", "attr2"
],
function(){
alert("attribute attr1 or attr2 of object has been changed");
});

object.watchOne("attr1", function(){
alert("attribute attr1 of object has been changed");
});

object.attr1 = "different value"; //will trigger a object.attr1 watch or object watchAll
//WORKS WITH ARRAYS TOO!
object.attr1.push("new item"); //will trigger a object.attr1 watch or object watchAll

@mspisars

This comment has been minimized.

Show comment Hide comment
@mspisars

mspisars Apr 3, 2012

I keep getting a "Uncaught TypeError: Cannot call method 'call' of undefined" on the handler on line 12 in the code above.
Is this a know problem? Is there a way to work around it? I am on Chrome.

mspisars commented Apr 3, 2012

I keep getting a "Uncaught TypeError: Cannot call method 'call' of undefined" on the handler on line 12 in the code above.
Is this a know problem? Is there a way to work around it? I am on Chrome.

@eligrey

This comment has been minimized.

Show comment Hide comment
@eligrey

eligrey Apr 3, 2012

You need to specify a handler function. I'm guessing that you're only calling object.watch(property) or the function you passed for the handler was null.

Owner

eligrey commented Apr 3, 2012

You need to specify a handler function. I'm guessing that you're only calling object.watch(property) or the function you passed for the handler was null.

@eligrey

This comment has been minimized.

Show comment Hide comment
@eligrey

eligrey Apr 3, 2012

I just raised the minimum requirements by only supporting Object.defineProperty, as __define[GS]etter__-only browsers are now an ancient minority. @ericcholis: object.watch and object.unwatch are also unenumerable now so that bug won't happen anymore.

Owner

eligrey commented Apr 3, 2012

I just raised the minimum requirements by only supporting Object.defineProperty, as __define[GS]etter__-only browsers are now an ancient minority. @ericcholis: object.watch and object.unwatch are also unenumerable now so that bug won't happen anymore.

@mspisars

This comment has been minimized.

Show comment Hide comment
@mspisars

mspisars Apr 3, 2012

No, the error was on page load. The new code does not throw the error, i just have to make sure everything else works.
Thanks for the quick update!

mspisars commented Apr 3, 2012

No, the error was on page load. The new code does not throw the error, i just have to make sure everything else works.
Thanks for the quick update!

@eligrey

This comment has been minimized.

Show comment Hide comment
@eligrey

eligrey Apr 3, 2012

The update had nothing to do with your issue, so you were probably calling object.watch too soon before a function was defined or something and later fixed it.

Owner

eligrey commented Apr 3, 2012

The update had nothing to do with your issue, so you were probably calling object.watch too soon before a function was defined or something and later fixed it.

@mahanmp

This comment has been minimized.

Show comment Hide comment
@mahanmp

mahanmp Apr 18, 2012

can you show some sample code on how to use this? thank you

mahanmp commented Apr 18, 2012

can you show some sample code on how to use this? thank you

@rwaldron

This comment has been minimized.

Show comment Hide comment
@rwaldron

rwaldron May 1, 2012

WTF with mixing comma first AND comma last in the same code?

rwaldron commented May 1, 2012

WTF with mixing comma first AND comma last in the same code?

@eligrey

This comment has been minimized.

Show comment Hide comment
@eligrey

eligrey May 1, 2012

@rwldrn Sorry, when I originally wrote this it was in comma-last form, and I forgot to completely update the code style in the recent update. I just fixed it.

Owner

eligrey commented May 1, 2012

@rwldrn Sorry, when I originally wrote this it was in comma-last form, and I forgot to completely update the code style in the recent update. I just fixed it.

@studiosmeeuw

This comment has been minimized.

Show comment Hide comment
@studiosmeeuw

studiosmeeuw Jun 7, 2012

Is IE8 still supported? When I try out a working page (in Safari, Chrome, ...) I get the following error:
"Message: Object doesn't support this property or method" on line 13.

Is IE8 still supported? When I try out a working page (in Safari, Chrome, ...) I get the following error:
"Message: Object doesn't support this property or method" on line 13.

@eligrey

This comment has been minimized.

Show comment Hide comment
@eligrey

eligrey Jun 8, 2012

Yes, but only for DOM objects.

Owner

eligrey commented Jun 8, 2012

Yes, but only for DOM objects.

@paul-d

This comment has been minimized.

Show comment Hide comment
@paul-d

paul-d Jun 19, 2012

This seems to be exactly what I was looking for, but will it work in all popular browsers/versions? My JS book doesn't even mention defineProperty.

paul-d commented Jun 19, 2012

This seems to be exactly what I was looking for, but will it work in all popular browsers/versions? My JS book doesn't even mention defineProperty.

@eligrey

This comment has been minimized.

Show comment Hide comment
@eligrey

eligrey Jun 19, 2012

It works with all current versions of all browsers. If you want to use it in IE8, it will only work on DOM objects.

Owner

eligrey commented Jun 19, 2012

It works with all current versions of all browsers. If you want to use it in IE8, it will only work on DOM objects.

@paul-d

This comment has been minimized.

Show comment Hide comment
@paul-d

paul-d Jun 19, 2012

Thank you. Apart from your solution, I haven't been able to find a way to tell if an object attribute changes, so I trust there is no solution that will work in browser versions in common use?

paul-d commented Jun 19, 2012

Thank you. Apart from your solution, I haven't been able to find a way to tell if an object attribute changes, so I trust there is no solution that will work in browser versions in common use?

@melanke

This comment has been minimized.

Show comment Hide comment
@melanke

melanke Jun 19, 2012

@eligrey a time a go I was working on a fork of your object-watch, great job by the way, and got the same problem (obvious), today I am working on another library that handle this problem. Not with the same possibilities but it is nice too. Note that I even tested it yet, maybe tomorrow it will be finished :)
You can find it here:
https://gist.github.com/2956493

melanke commented Jun 19, 2012

@eligrey a time a go I was working on a fork of your object-watch, great job by the way, and got the same problem (obvious), today I am working on another library that handle this problem. Not with the same possibilities but it is nice too. Note that I even tested it yet, maybe tomorrow it will be finished :)
You can find it here:
https://gist.github.com/2956493

@ItsLeeOwen

This comment has been minimized.

Show comment Hide comment
@ItsLeeOwen

ItsLeeOwen Aug 9, 2012

Is there anything out there to watch all changes to properties of an object?

Is there anything out there to watch all changes to properties of an object?

@afraser

This comment has been minimized.

Show comment Hide comment
@afraser

afraser Sep 28, 2012

This plus debugger; in Chrome = tasty.

afraser commented Sep 28, 2012

This plus debugger; in Chrome = tasty.

@ceanela

This comment has been minimized.

Show comment Hide comment
@ceanela

ceanela Oct 9, 2012

ItsLeeOwen, I might be two months late, but maybe you should run a for loop to add watch to each property object. That seems the pretty quick and simple.

ceanela commented Oct 9, 2012

ItsLeeOwen, I might be two months late, but maybe you should run a for loop to add watch to each property object. That seems the pretty quick and simple.

@razola

This comment has been minimized.

Show comment Hide comment
@razola

razola Dec 22, 2012

Thanks for this one!

Would calling unwatch from within the watch function for any reason potentially cause problems?

razola commented Dec 22, 2012

Thanks for this one!

Would calling unwatch from within the watch function for any reason potentially cause problems?

@XoseLluis

This comment has been minimized.

Show comment Hide comment
@XoseLluis

XoseLluis Feb 10, 2013

Hi there,
many thanks for this polyfill, but I've found a problem with it. It won't work for watching accessor properties (the ones with a get/set), while the original Mozilla's function does.
So, I've rolled my own version here:
https://gist.github.com/XoseLluis/4750176

Hi there,
many thanks for this polyfill, but I've found a problem with it. It won't work for watching accessor properties (the ones with a get/set), while the original Mozilla's function does.
So, I've rolled my own version here:
https://gist.github.com/XoseLluis/4750176

@aeosynth

This comment has been minimized.

Show comment Hide comment
@aeosynth

aeosynth Feb 11, 2013

is this compatible with harmony:observe?

is this compatible with harmony:observe?

@cannapages

This comment has been minimized.

Show comment Hide comment
@cannapages

cannapages May 9, 2013

Awesome thank you!

Awesome thank you!

@qhedges

This comment has been minimized.

Show comment Hide comment
@qhedges

qhedges May 15, 2013

What if the property already has a getter and setter. Doesn't this override them?

qhedges commented May 15, 2013

What if the property already has a getter and setter. Doesn't this override them?

@juriseng

This comment has been minimized.

Show comment Hide comment
@juriseng

juriseng Dec 4, 2013

Thanks so much, this snippet saved me! :)

juriseng commented Dec 4, 2013

Thanks so much, this snippet saved me! :)

@jslegers

This comment has been minimized.

Show comment Hide comment
@jslegers

jslegers Dec 7, 2013

Seems like a pretty elegant and optimal solution...

Nice job !

jslegers commented Dec 7, 2013

Seems like a pretty elegant and optimal solution...

Nice job !

@jslegers

This comment has been minimized.

Show comment Hide comment
@jslegers

jslegers Dec 7, 2013

I tried the following example from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch :

var o = { p: 1 };

o.watch("p", function (id, oldval, newval) {
    console.log( "o." + id + " changed from " + oldval + " to " + newval );
    return newval;
});

o.p = 2;
o.p = 3;
delete o.p;
o.p = 4;

o.unwatch('p');
o.p = 5;

The code breaks after the 'delete' statement. Firefox (using its native implementation) still triggers the 'watch' statement while Chrome (using the polyfill) doesn't. It's a minor issue, but I figured it's still worth mentioning...

When I remove the 'delete' statement, both both browsers are in synch.

jslegers commented Dec 7, 2013

I tried the following example from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/watch :

var o = { p: 1 };

o.watch("p", function (id, oldval, newval) {
    console.log( "o." + id + " changed from " + oldval + " to " + newval );
    return newval;
});

o.p = 2;
o.p = 3;
delete o.p;
o.p = 4;

o.unwatch('p');
o.p = 5;

The code breaks after the 'delete' statement. Firefox (using its native implementation) still triggers the 'watch' statement while Chrome (using the polyfill) doesn't. It's a minor issue, but I figured it's still worth mentioning...

When I remove the 'delete' statement, both both browsers are in synch.

@dtpz

This comment has been minimized.

Show comment Hide comment
@dtpz

dtpz Dec 8, 2013

Hi!

Thanks, this is great - I created my own version after seeing yours here:
https://github.com/dtpz/DataWatch/blob/master/DataWatch.js

It takes what you did to the next level by allowing mutation of the set value (though this must be explicit), taking it off of the object prototype, and allowing multiple watchers and possibility to unwatch a specific function (the same way it's done with events).

Please tell me what you think - and thanks!

dtpz commented Dec 8, 2013

Hi!

Thanks, this is great - I created my own version after seeing yours here:
https://github.com/dtpz/DataWatch/blob/master/DataWatch.js

It takes what you did to the next level by allowing mutation of the set value (though this must be explicit), taking it off of the object prototype, and allowing multiple watchers and possibility to unwatch a specific function (the same way it's done with events).

Please tell me what you think - and thanks!

@Zeokat

This comment has been minimized.

Show comment Hide comment
@Zeokat

Zeokat Feb 24, 2014

Very usefull piece of code, you saved my day. Thanks.

Zeokat commented Feb 24, 2014

Very usefull piece of code, you saved my day. Thanks.

@stefek99

This comment has been minimized.

Show comment Hide comment
@stefek99

stefek99 Mar 15, 2014

Someone up above mentioned that the setter function does not work properly:

a = {b:"c", d:"e"}
   Object {b: "c", d: "e"}

a.watch("b", function() { console.log("change, new a: ", a) } ) 
   undefined

a.b = "new value of B"
   change, new a:  Object {d: "e", b: undefined}
   "new value of B"

a
   Object {d: "e", b: undefined}

UPDATE: 16 Sep 2015 - so happy that I've found my comment - the thing does not work for me. It wasn't working a year ago, it isn't working now.

Someone up above mentioned that the setter function does not work properly:

a = {b:"c", d:"e"}
   Object {b: "c", d: "e"}

a.watch("b", function() { console.log("change, new a: ", a) } ) 
   undefined

a.b = "new value of B"
   change, new a:  Object {d: "e", b: undefined}
   "new value of B"

a
   Object {d: "e", b: undefined}

UPDATE: 16 Sep 2015 - so happy that I've found my comment - the thing does not work for me. It wasn't working a year ago, it isn't working now.

@luisnomad

This comment has been minimized.

Show comment Hide comment
@luisnomad

luisnomad Mar 31, 2014

Awesome, thank you!

Awesome, thank you!

@adriengibrat

This comment has been minimized.

Show comment Hide comment
@adriengibrat

adriengibrat Jul 20, 2014

@XoseLluis has proposed a great imporvement to this piece of code,
I've rewrote it, optimized for minification + included some tests :
https://gist.github.com/adriengibrat/b0ee333dc1b058a22b66

The only limitation is, as @jslegers mentioned, that deleting a property remove the watchpoint !

@XoseLluis has proposed a great imporvement to this piece of code,
I've rewrote it, optimized for minification + included some tests :
https://gist.github.com/adriengibrat/b0ee333dc1b058a22b66

The only limitation is, as @jslegers mentioned, that deleting a property remove the watchpoint !

@koolb

This comment has been minimized.

Show comment Hide comment
@koolb

koolb Aug 25, 2014

Thanks for this. Here's the coffee version (https://gist.github.com/koolb/fb9c8238372590814e34):
if (not Object::watch?)
Object.defineProperty Object.prototype, "watch",
enumerable: false, configurable: true, writeable: false, value: (prop, handler) ->
oldval = @[prop]
newval = oldval
getter = () -> newval
setter = (val) -> oldval = newval; newval = handler.call(@, prop, oldval, val)
Object.defineProperty @, prop, get: getter, set: setter, enumerable: true, configurable: true if delete @[prop]

if (not Object::unwatch?)
Object.defineProperty Object.prototype, "unwatch",
enumerable: false, configurable: true, writeable: false, value: (prop) ->
prop = @[prop]
delete @[prop]
@[prop] = val

koolb commented Aug 25, 2014

Thanks for this. Here's the coffee version (https://gist.github.com/koolb/fb9c8238372590814e34):
if (not Object::watch?)
Object.defineProperty Object.prototype, "watch",
enumerable: false, configurable: true, writeable: false, value: (prop, handler) ->
oldval = @[prop]
newval = oldval
getter = () -> newval
setter = (val) -> oldval = newval; newval = handler.call(@, prop, oldval, val)
Object.defineProperty @, prop, get: getter, set: setter, enumerable: true, configurable: true if delete @[prop]

if (not Object::unwatch?)
Object.defineProperty Object.prototype, "unwatch",
enumerable: false, configurable: true, writeable: false, value: (prop) ->
prop = @[prop]
delete @[prop]
@[prop] = val

@franleplant

This comment has been minimized.

Show comment Hide comment
@franleplant

franleplant Sep 22, 2014

This is really nice! (comma first styling makes me want to kill my self though)

This is really nice! (comma first styling makes me want to kill my self though)

@flackjap

This comment has been minimized.

Show comment Hide comment
@flackjap

flackjap Nov 9, 2014

If anyone else comes by and needs a version of this that doesn't calls back when the newly set value of an object key is the same as previous, here's my fork:

https://gist.github.com/flackjap/f318e6a2b316e4d9fa44

flackjap commented Nov 9, 2014

If anyone else comes by and needs a version of this that doesn't calls back when the newly set value of an object key is the same as previous, here's my fork:

https://gist.github.com/flackjap/f318e6a2b316e4d9fa44

@robianmcd

This comment has been minimized.

Show comment Hide comment
@robianmcd

robianmcd Mar 3, 2015

I can't get this working with DOM Elements. e.g. https://gist.github.com/robianmcd/ee9a5f10dca11e357c9c

Am I doing something wrong?

I can't get this working with DOM Elements. e.g. https://gist.github.com/robianmcd/ee9a5f10dca11e357c9c

Am I doing something wrong?

@MikeGarde

This comment has been minimized.

Show comment Hide comment
@MikeGarde

MikeGarde Apr 9, 2015

I wanted to add a few keywords for people searching for this type of solution, I am using this with Node.JS / Express.JS and it works perfectly!

Thanks

I wanted to add a few keywords for people searching for this type of solution, I am using this with Node.JS / Express.JS and it works perfectly!

Thanks

@webarthur

This comment has been minimized.

Show comment Hide comment
@LinBoLen

This comment has been minimized.

Show comment Hide comment
@LinBoLen

LinBoLen Feb 17, 2016

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

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

@achillesrasquinha

This comment has been minimized.

Show comment Hide comment
@achillesrasquinha

achillesrasquinha Apr 27, 2016

Excellent!

Excellent!

@nigayo

This comment has been minimized.

Show comment Hide comment
@nigayo

nigayo Jul 9, 2016

Thanks for this one.

nigayo commented Jul 9, 2016

Thanks for this one.

@rokobuljan

This comment has been minimized.

Show comment Hide comment
@rokobuljan

rokobuljan Nov 10, 2016

Seems there's an issue undefinedon the oldval

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

rokobuljan commented Nov 10, 2016

Seems there's an issue undefinedon the oldval

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

@Swivelgames

This comment has been minimized.

Show comment Hide comment
@Swivelgames

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

@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

This comment has been minimized.

Show comment Hide comment
@MMDF

MMDF 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!

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

This comment has been minimized.

Show comment Hide comment
@alierdogan7

alierdogan7 Apr 9, 2017

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

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

@georgir

This comment has been minimized.

Show comment Hide comment
@georgir

georgir 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.

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.

@mateuszgwozdz

This comment has been minimized.

Show comment Hide comment
@mateuszgwozdz

mateuszgwozdz Jul 28, 2017

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

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

@Erutan409

This comment has been minimized.

Show comment Hide comment
@Erutan409

Erutan409 Mar 9, 2018

@mateuszgwozdz Vue.js can do it.

@mateuszgwozdz Vue.js can do it.

@Erutan409

This comment has been minimized.

Show comment Hide comment
@Erutan409

Erutan409 Mar 9, 2018

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

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

@chack1172

This comment has been minimized.

Show comment Hide comment
@chack1172

chack1172 Apr 18, 2018

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

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

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