Figuring out the behavior of WindowProxy in the face of non-configurable properties

Ian Hickson ian at
Wed Jan 14 19:14:29 PST 2015

On Wed, 14 Jan 2015, Boris Zbarsky wrote:
> The behavior of ES objects is expressed in terms of various internal methods.
> That's what you have to do to express what an ES object does.

Not necessarily. We can also just say "WindowProxy is its own thing and 
here is how it works".

> > No. WindowProxy isn't an ES Proxy.
> It's an ES object.

That's debatable.

> > It is indistinguishable from the Window object.
> It's distinguishable in various ways, including things like "if I get 
> this property from it in 5 seconds, will I get the same value as from 
> the Window?" The answer to that is "maybe not".

No, because by the time it returns a different value, it no longer acts 
like it's the same object.

You're holding a magical thing that looks and acts exactly like a potted 
plant. It's indistinguishable from a potted plant. Then five seconds 
later, you're holding a cat. It's indistinguishable from a cat. You can't 
tell that the potted plant and the cat are the same thing. You can presume 
that since you were holding one, and then you were holding the other, they 
might have some relationship, but there's no way to tell that they're the 
same thing. Even if the assume they're the same thing, you can't tell the 
difference between the being the same thing, and someone just quickly 
stealing the potted plant and replacing it with a cat.

> > When the WindowProxy changes what it's pointing at, it's exactly as if 
> > the browser had reached in and changed every WindowProxy that pointed 
> > to the former and made it point to the latter.
> You say "every WindowProxy", but in practice in an ES implementation you 
> have some object, it has some internal methods.  This is the last time 
> I'm bothering to go through this with you, since clearly we're getting 
> nowhere, as I said in 

You are dismissing what I'm describing as being a misunderstanding of how 
things should be considered to work, because they're not the same as what 
you're describing. But maybe what I'm describing is how things should be 
considered to work, and what you're describing is wrong. Or maybe both our 
points of view are valid, and we should figure out which is easiest to 
describe, or easiest to implement, or simplest to explain to authors, or 
most compatible with the Web, or least likely to involve contortions 
around unnecessary invariants, or whatever other priorities we want to 
apply to this decision.

> The internal methods of every object must have behavior that preserves 
> the invariants.
> For ES proxies, the internal methods are defined in the spec in a way 
> that preserves the invariant.
> For other ES objects they are also defined in the spec.
> ES also allows other "exotic objects" that define some other behavior 
> for those internal methods, but requires that the invariants be 
> preserved.

So one option would be to just say that WindowProxy is not an ES object.

> > > It doesn't matter.  The user sees the WindowProxy, not the Window.
> > 
> > No. What the author has is a WindowProxy, but in every sense it acts 
> > like a Window.
> You mean in every sense except what property values you'll get five 
> seconds from now.

Five seconds from now, the author will in every sense appear to have a 
different Window. It still appears to be a Window. Just a different one.

> > > After you navigate, you still have the same WindowProxy (e.g. 
> > > .contentWindow returns something that is === to the thing you had 
> > > before you navigated).
> > 
> > You have no way to actually test this. Since every reference to the 
> > old Window is now a reference to the new Window, you have no way to 
> > test if the WindowProxy references something new.
> === on objects tests object identity.

Except on WindowProxy, because WindowProxy forwards all operations to the 
underlying Window.

> It's not affected by internal methods in any way.  Therefore, if === 
> returns true then you actually have the same object.


   let a = {};
   let b = {};

   let c = a;
   let d = a;

   assert(c === d); // true


   assert(c === d); // still true

If the opaqueCode() function just does:

   function opaqueCode() {
     c = b;
     d = b;

...then === doesn't help you tell that c and d have changed identity. They 
are still triple-equals to each other, but they're different objects.

This is exactly what happens with WindowProxy, except that the browser is 
the code doing opaqueCode().

> >     // part 1
> >     let a = {};
> >     let b = {};
> >     let c = a;
> > 
> >     // part 2
> > = 1;
> > 
> >     // part 3
> >     c = b;
> > 
> >     // part 4
> >     console.log(;
> > 
> > Is it surprising that the log doesn't log "1"?
> None of this affects the invariants involved.

The point is that the invariants apply to the actual objects originally 
assigned to a and b, they don't apply to the variables.

> > This is what is going on here, except that part 3 is done by the 
> > browser.
> No, because in the code above if I do |var d = c;| then the d won't 
> change in part 3.

If in the code above you do var d = c, then add d = b to part 3 to 
simulate what the browser does.

> Having an object with sane internal methods here is really much simpler 
> than magic "update all the references" behavior. But again, I've said 
> this to you numerous times.

I'm not actually proposing updating all the references. That's just a 
convenient way to think about it that is isomorphic in behaviour to what 
is specced. What is specced is just that you have a placeholder 
pseudo-object that forwards all behaviour to an underlying object, where 
which object it's forwarding to can change over time.

> Let me try it again: the fact that the definition in the HTML spec has 
> not lead to interop is not an accident.  It's not something browsers can 
> sanely achieve interop on because it involves handwavy magic that they 
> are extremely likely to interpret differently.  On the other hand, 
> defining a single object with internal methods that do what you want 
> would be _very_ clear to an DOM or JS engine implementor.

I have asked before, but would like to reiterate:

If there is any behaviour that is underdefined by the HTML spec's current 
prose, please tell me, so that I can spec it.

> > It looks and quacks like a Window.
> No, it, doesn't, see above.

It is literally indistinguishable from _a_ Window in every way at all 
times. That's the whole point. Which Window it appears to be 
indistinguishable from at any particular time varies over time.

> > It turns out that it does have such a type. WindowProxy is it. I agree 
> > that that makes it a special snowflake.
> My point is that this special snowflake is unnecessary and confusing.

Well it predates all the ES6 stuff we're talking about here by several 
years, so I'd argue that the confusion doesn't stem from WindowProxy. I 
also don't really agree that it's confusing. It's really simple to 
explain, certainly much simpler than anything involving ES proxies and so 
forth. It's one sentence in the spec, and as far as I'm aware, it doesn't 
leave anything undefined.

I also disagree that what the spec says doesn't match implementations. I 
think it matches implementations pretty darn closely. I mean, in 
particular, it matches exactly what Travis described as IE's 
implementation. (This is not an accident; matching implementations was one 
of the main goals of the HTML spec, and at the time this was specced, IE 
was by far the biggest UA out there.)

Ian Hickson               U+1047E                )\._.,--....,'``.    fL       U+263A                /,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'

More information about the es-discuss mailing list