Proxy on window

Short answer is no. You can't use a proxy for this. It is always better to revise and refactor your app to get rid of need to do such shenanigans. But I know that sometimes we have no time to do things right. Althrough I don't recommend you to do this, you still can get a changes on window object.

You have a couple of options to do this. If you know a list of vars you're looking for, you can use something like Watch.JS Basically it is able to track all the changes, but I wasn't able to make it work reliably so it is better to specify a list

watch(window, ['list', 'of', 'vars'], (prop, action, newVal, oldVal) => {
    console.log('Property changed', prop, action, newVal, oldVal);
}, 1);

As an alternative, you can create a simple dirty checker

let props = Object.keys(window);
const check = () => {
    const currentProps = Object.keys(window);
    const newProps = currentProps.filter(item => props.indexOf(item) === -1);
    if (newProps.length) {
        console.log('Added these properties', newProps);
        props = currentProps;
    }
    requestAnimationFrame(check);
};
requestAnimationFrame(check);

But in case you decided to go with either solution, you have to make sure all checks will stop when needed to avoid memory leaks, or CPU consumption. This check code is not consuming too much but it could in theory. So you have to keep an eye on it. On empty page profile data looks like this profile data

And remember to use unwatch in case of Watch.JS or to add a condition to stop the checks in case you use the second solution once they will complete the job


Proxy is slow and shouldn't be used in performance-critical places, while window affects the entire application and certainly could be considered performance-critical.

But the window property is read-only, i.e. it is non-configurable and has no set accessor, it can't be replaced with a proxy.

The alternative to Proxy that can spy on window changes is Firefox-specific watch method, it can be used in scripts that run in Firefox (e.g. extensions) but not anywhere else. V8-specific Object.observe was unable to observe window by design, also, it was removed from Chrome and other V8 browsers.

Generally this can be achieved by polling window properties:

let oldProps;

setInterval(() => {
  console.time('Polling window');
  let newProps = Object.getOwnPropertyNames(window);

  if (oldProps) {
    let addedProps = newProps.filter(prop => oldProps.indexOf(prop) < 0 );
    console.log('Added props', addedProps);
  }
  oldProps = newProps;
  console.timeEnd('Polling window');
}, 500);

If this code is supposed to be used in production, it should be optimized, because filter is relatively slow, and indexOf traverses the entire array on each iteration, this results in very inefficient code.

Raw for or while loop is the way to go:

let oldProps;

setInterval(() => {
  console.time('Polling window');
  let newProps = Object.getOwnPropertyNames(window).sort();

  if (oldProps) {
    for (let oldI = 0, newI = 0; oldI < oldProps.length || newI < newProps.length; oldI++, newI++) {
      let oldProp = oldProps[oldI];
      let newProp = newProps[newI];

      if (newProp > oldProp || newProp === undefined) {
        newI--;
        console.log('Removed prop', oldProp);
      } else if (newProp < oldProp || oldProp === undefined) {
        oldI--;
        console.log('Added prop', newProp);
      }
    }
  }
  oldProps = newProps;
  console.timeEnd('Polling window');
}, 500);

Youre actually not trying to trigger the window proxy. You need to do:

let proxy = new Proxy(window, handler);
proxy.foo = 'bar';

And no, you cant do

window = new Proxy(window, handler);

as window is unreplaceable.


Yes window is unreplaceable, but you can wrap the tested code with a fake proxified window:

let handler = {
   defineProperty(target, key, descriptor) {
     console.log('hey', key);
     return false;
   }
 };

let proxyWindow = new Proxy(window, handler);

(function(window){
   
 //js
 window.foo = 'bar';

}.bind(proxyWindow,proxyWindow).call(proxyWindow));

If the tested code is not too complicated, this will be OK, as leaks to the actual window object may occur (ex: setTimeout etc) but these can be patched too.