11

How do I constantly check a variables value. For example:

if(variable == 'value'){
    dosomething();
}

This would work if I constantly looped it or something, but is there an efficient way of triggering that as soon as the variable is set to that value?

franzlorenzon
  • 5,845
  • 6
  • 36
  • 58
Connor
  • 111
  • 1
  • 1
  • 4
  • 1
    With a timer. I think there is no other way – Pekka Jan 08 '11 at 01:50
  • There are some implementation specific ways. Do you have a target browser, or just as many as possible? – Hemlock Jan 08 '11 at 01:54
  • I am creating a mobile app, so I have all of the latest Javascript techniques and best practices supported as the JS is converted to Objective C. I am not setting the value of the function, it is being given dynamically from a 3rd party when a user clicks a button. I am waiting for that value to change from default to anything else. – Connor Jan 08 '11 at 02:05
  • 1
    So, can I assume you'll be running this on webkit? If so perhaps you should state that and add a webkit and/or safari tag because it may have ways to do this that other browsers can't. – slebetman Jan 08 '11 at 02:52

6 Answers6

12

This solution use deprecated APIs. Computed properties and proxies are a better alternative except on the oldest browsers. See K2Span's answer for an example of how to use those.

Object.watch:

Watches for a property to be assigned a value and runs a function when that occurs.

Object.watch() for all browsers? talks about cross-browser ways to do Object.watch on browsers that don't support it natively.

Mike Samuel
  • 118,113
  • 30
  • 216
  • 245
  • 1
    +1 Most efficient way, and if you want to watch global variable you could use window.watch('variable', handler); – Amjad Masad Jan 08 '11 at 01:59
  • I am creating a mobile app, so I have all of the latest Javascript techniques and best practices supported as the JS is converted to Objective C. I am not setting the value of the function, it is being given dynamically from a 3rd party when a user clicks a button. I am waiting for that value to change from default to anything else. – Connor Jan 08 '11 at 02:04
  • lets assume variable is global: function handler(oldval, newval){if (oldval!=newval) //do something} window.watch('variable', handler); – Amjad Masad Jan 08 '11 at 02:30
  • `I am creating a mobile app... converted to Objective C` What connor means is that he'll be running this code in webkit. So he's looking for webkit/safari specific technique. – slebetman Jan 08 '11 at 02:55
  • what about a global array ? – maazza Jun 11 '13 at 13:33
  • @maazza, do you want to know when the contents of the global array changes, or when an assignment to the global property changes the array that is referenced? – Mike Samuel Jun 11 '13 at 16:22
  • The answer should cover the second, and I believe `Object.watch` on Firefox works on arrays for individual elements and for the length property, so `var arr = ['foo']; arr.watch(0, function () { alert('element 0 changed'); }); arr.watch('length', function () { alert('length changed'); });` should work as expected so you could watch the length so you know which indices to watch. I don't know if the `Object.watch` substitutes on other platforms also work this way with arrays though. – Mike Samuel Jun 11 '13 at 18:02
  • 1
    _"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."_ Direct from the above Link. – Mark Carpenter Jr Jun 26 '17 at 13:57
  • @MarkCarpenterJr yes because it is just a fancy name for setInterval. – Aero Wang Oct 13 '17 at 17:15
  • 1
    This method is deprecated from version 58 of Firefox and it is not recommended at all. – ali Nov 12 '20 at 16:12
  • @ali, Added a note to the front that this answer is mostly of historical interest and linked to a more modern answer. – Mike Samuel Nov 18 '20 at 21:31
8
Object.defineProperty(Object.prototype, 'watch', {
    value: function(prop, handler){
        var setter = function(val){
            return val = handler.call(this, val);
        };
        Object.defineProperty(this, prop, {
            set: setter
        });
    }
});

How to use:

var obj = {};

obj.watch('prop', function(value){
    console.log('wow!',value);
});

obj.prop = 3;
K2Spam
  • 81
  • 1
  • 3
  • 3
    Can you explain how this works please? It seems to work great, but I'm not really following how :) – 1252748 Feb 03 '17 at 18:42
  • I think this answer is awesome. It injects a callback into "set" property of an object property (the variable under watch). – Gonki Oct 16 '19 at 05:25
  • This assumes that the watched property isn't already covered by a function that does stuff to the value. It will clobber any setter code currently in place. And how would one implement `obj.unwatch()`? And what if another piece of code is already watching this? It will clobber the previous watcher, yes? Seems like a better solution might be something like `obj.addListener('change', prop, listener);` maybe? – user1944491 Nov 25 '20 at 16:12
6

Use setInterval:

var key = ''
setInterval(function(){
  if(key == 'value'){
    dosomething();
  }
}, 1000);
Chandu
  • 81,493
  • 19
  • 133
  • 134
  • This is a useful answer for a different question. Most of the time you won't discover property changes, since they'll happen between ticks of the function. – James Moore Jul 31 '12 at 16:00
4

As @Pekka commented, you can have a timer constantly poll the variable. A better solution, if it's all your code that's changing the variable, is to not just set the variable directly, but rather have all setters call a function. The function could then set the variable and do any additional processing you need.

function setValue(value) {
    myVariable = value;
    notifyWatchers();
}
Jacob
  • 77,566
  • 24
  • 149
  • 228
4

If you encapsulate your variable so that the value can only be set by calling a function, it gives you the opportunity to check the value.

function ValueWatcher(value) {
    this.onBeforeSet = function(){}
    this.onAfterSet = function(){}

    this.setValue = function(newVal) {
        this.onBeforeSet(value, newVal)
        value = newVal;
        this.onAfterSet(newVal)
    }
    this.getValue = function() {
        return value;
    }
}

var name = new ValueWatcher("chris");

wacthedName.onBeforeChange = function(currentVal, newVal) {
    alert("about to change from" + currentVal + " to " + newVal);
}

name.setValue("Connor");
goat
  • 31,486
  • 7
  • 73
  • 96
0

I had a similar problem and was able to eliminate it using a timed function that I had used earlier. Even if you don't have a timed function there are easy to create;

var rand = 0
setInterval(function senseConst () {if (rand = 0) {rand = x}, 10);
//x could be equal to the variables value that you want to check

I used this to constantly have a variable that is the length of the page by making using the following code

var widthSensorOutput = 0
setInterval(function senseConst () {if (widthSensorOutput = 0) {widthSensorOutput = document.getElementById('widthSensor').clientWidth}, 10);
//'widthSensor' is a div with the width equal to 100%

I am not sure if this is the best way to solve your problem but it worked for me. To be clear, this is the the same basic code that Chandu gave, just I added what you should do once you are inside the function, which already is pretty obvious. I did not understand Chandu's post and did not realize that they used the same root code.

FireTiger
  • 79
  • 5