6

I have a global variable and its type is String:

window.my_global_var = 'string';

It might be changed by some external-loaded JavaScript files or an AJAX request. So I want to watch it and invoke a callback when it's updated.

I searched a while but found Object.observe is already deprecated. I found an answer but it is better used to observe an object, not a String window.variable.

The worst approach would be using a setInterval to watch it but I guess it's too stupid.

Is there any good way to do this?

AGamePlayer
  • 7,404
  • 19
  • 62
  • 119

2 Answers2

5

You can use Object.defineProperties on window:

function onValueUpdate(my_global_var) {
   // Some arbitrary logic you want to execute on callback
   console.log(`my_global_var was updated: ${my_global_var}`);
}

Object.defineProperties(window, {
    _my_global_var: {
        value: 'string',
        writable: true
    },
    my_global_var: {
        get: function() {
            return this._my_global_var;
        },
        set: function(val) {
            this._my_global_var = val;
            onValueUpdate(this._my_global_var);
        }
    }
});

window.my_global_var = 'New string';

When you access window.my_global_var it behaves exactly as the property of type String would. But when you set it you can adjust it to use any additional logic.

Function onValueUpdate needs to be public (or you can use a public method instead).

There’s a warning against this approach in the answer you’ve found though:

I'd not go with getters/setters solution - it's complicated, not scalable and not maintainable.

So if you need scalability you probably should look for some library that can do that. Otherwise this should work just as well.

genechk
  • 369
  • 1
  • 4
  • 2
    One minor addition, there's no need for `onValueUpdate` to be global, it just has to be in scope for the setter. – Etheryte Oct 24 '20 at 14:46
  • This is a nice little util. Our application has a bunch of stuff assigned to the window, which we would like to remove. Now we can trace where the global object is used and fix it. – Alex McCabe Jul 20 '23 at 10:51
2

You could wrap the global object in a proxy with a set handler. You would need to pass the proxy around your program, rather than relying implicitly on the global object, however.

const handler = {
  set(obj, prop, value) {
    if (prop === 'foo')
      console.log(`Property updated with value: ${value}!`)
    return Reflect.set(...arguments)
  }
};

const proxy = new Proxy(window, handler);
proxy.foo = 1 // "Property updated with value: 1!"
proxy.bar = 2 

console.log(foo) // 1
console.log(bar) // 2
Ben Aston
  • 53,718
  • 65
  • 205
  • 331