JS Tip of the Day: The Window Proxy

The Window Proxy
Level: Intermediate

The global object in browsers is represented by window. This is the object with all of the built-in definitions for the language (and the Web API) as well as the container for all of your global properties and declarations that are accessible from anywhere. When you access window, though, you’re not actually accessing THE window. Rather, what you’re getting is a WindowProxy.

A WindowProxy is a wrapper around a real window/global object. WindowProxy objects store a window object in an internal slot ([[Window]]) and forward all your operations on it to that internal window reference. Any assignments made to a WindowProxy, for example, will in turn become assignments to the real window object it wraps. For the most part, you won’t even know this wrapper exists. However, it can become apparent when a WindowProxy gets a new window reference.

When a browser window loads a new document (or reloads the current) the current WindowProxy does not change. Instead, the internal window it references internally changes. The result of this is that it looks like there’s a new window object, but any references to the original window will still continue to function as valid references to the new window. You can easily see this in action using iframes.

<iframe id="frame" src="frame.html"></iframe>

<script>
let frame = document.getElementById('frame');
let savedWindow; // stores frame's window object

function firstLoad () {
    savedWindow = frame.contentWindow; // window in the frame
    savedWindow.savedValue = 'data'; // global variable

    frame.onload = secondLoad;
    savedWindow.location.reload();
}
function secondLoad () {
    console.log(savedWindow === frame.contentWindow); // true
    console.log(savedWindow.savedValue); // undefined
}
frame.onload = firstLoad;
</script>

In this example, the savedWindow variable was used to store the window (contentWindow) of the iframe when it first loads. Along with that, a new property called savedValue is getting assigned there. When the frame page is reloaded, the old savedWindow reference continues to point to the now new page’s window though the savedValue property is no longer available. This is because the WindowProxy object didn’t change - what savedWindow refers to - only its internal window reference. And it was that internal window is where savedValue set earlier was actually stored. That window is no longer available because it was replaced in the WindowProxy with a new window as a result of the page getting reloaded.

The fact that window objects are really WindowProxy objects generally shouldn’t affect your everyday usage of window objects. But if you’re working with frames, you may see some weirdness around window references which could be explained by the fact that they’re really WindowProxy references and not direct references to the window global.

More info: