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.)
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);