0

I need to Proxy a window object opened with window.open.

So far as I understand it (which is not well), the trivial "handler" here should effectively be the identity operation, passing thru property accesses unmodified:

let origOpen = window.open;
window.open = function(url) {
  let openedWindow = origOpen.apply(this, arguments);
  let handler = {
    get(target, prop, receiver) {
      return Reflect.get(...arguments);
    }
  };
  let wrappedWindow = new Proxy(openedWindow, handler);
  return wrappedWindow;
};

let wi = window.open("https://example.net/");
console.log(wi.closed);

However, when this script reaches the line which tries to log wi.closed, it throws the following exception:

Uncaught TypeError: 'get closed' called on an object that does not implement interface Window.

(Using Firefox ESR 115.)

2
  • Try Reflect.get(target, prop, target) instead of Reflect.get(target, prop, receiver) for builtin getters. You'd have the same problem for methods though Commented May 10, 2024 at 12:33
  • 1
    Why exactly do you need a proxy? Commented May 10, 2024 at 12:35

1 Answer 1

2

Unfortunately native objects like Window, Event, RegExp, etc. in general don't support calling their methods and getters/setters on their proxied versions, you should call them yourself with the original object.

Here the getter closed belongs to the window, in other cases it could belong to an instance's prototype (to any prototype in the prototype chain). So the logic of finding a getter could be more complex.

For methods you could either return a proxy of a method with the apply trap where you call the method with the proper this or like in my example just bind this.

The same should be applied for setters.

Note that a returned value from a getter could be a function too, so you should bind it also. Thus the whole logic to cover all cases in generic manner could be quite complicated.


    let origOpen = window.open;
    window.open = function(url) {
      let openedWindow = origOpen.apply(this, arguments);
      let handler = {
        get(target, prop){    
          // bind methods to the original object
          if(typeof target[prop] === 'function') return target[prop].bind(target);
          // call getters with the original object
          const desc = Object.getOwnPropertyDescriptor(target, prop);
          if(desc?.get) return desc.get.call(target);

          return Reflect.get(...arguments);
        }
      };
      return new Proxy(openedWindow, handler);
    };

    let wi = window.open("https://example.net/");
    console.log(wi.closed);

Sign up to request clarification or add additional context in comments.

1 Comment

This is the kind of yucky stuff I was hoping Proxy would avoid, but it does now work for all the properties and methods I needed. Thanks.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.