Re: variable declarations shadowing named properties on window

On Tue, Jan 3, 2012 at 4:51 PM, Cameron McCormack <cam@mcc.id.au> wrote:

> In https://www.w3.org/Bugs/**Public/show_bug.cgi?id=8241<https://www.w3.org/Bugs/Public/show_bug.cgi?id=8241>we finally settled on the name resolution order for the window object to be
> the following:
>
>  1. Own properties on window (which would include JS builtin
>     global properties like Array, Object, etc.) and global variables
>  2. Properties from the prototype chain (which would include
>     "constructor" & event listener properties)
>  3. Frames
>  4. Global scope polluter
>
> Since the Window interface is also declared with
> [ReplaceableNamedProperties], allowing assignments to window object
> properties to shadow named properties, the following document should alert
> "[object Window]" and then "a":
>
>  <!DOCTYPE html>
>  <iframe name=x></iframe>
>  <script>
>    alert(x);
>    x = "a";
>    alert(x);
>  </script>
>
> The question I have (which Ojan raised in the content of
> http://code.google.com/p/**chromium/issues/detail?id=**80591<http://code.google.com/p/chromium/issues/detail?id=80591>)
> is what the following document should alert:
>
>  <!DOCTYPE html>
>  <iframe name=x></iframe>
>  <script>
>    alert(x);
>  </script>
>  <script>
>    var x;
>    alert(x);
>  </script>
>
> I had thought that current specs would cause this to alert "[object
> Window]" and then "undefined" (which I think is preferable to the
> alternative) but now looking closer I don't think this is true.
>
> Here's current browser behaviour:
>
> Firefox nightly:       "[object Window]" / "[object Window]"
> Opera.next:            "[object Window]" / "undefined"
> Safari/WebKit nightly: "[object DOMWindow]" / "[object DOMWindow]"
> Chrome nightly:        "[object DOMWindow]" / "[object DOMWindow]"
> IE 10pp1:              "[object Window]" / "undefined"
>

Firefox behaves differently for frames and elements I believe (or maybe
names versus IDs?).

<div id="a"></div><script>alert(a);</script> // Alerts "[object
HTMLDivElement]"
<div id="a"></div><script>alert(a);var a;</script> // Alerts "undefined"
<div id="a"></div><script>var a;alert(a);</script> // Alerts "undefined"

My strong preference is that declaring a variable should cause it to shadow
(i.e. alert undefined above). Not shadowing has been a frequent source of
bugs for the Closure Compiler in WebKit. Shadowing makes it much easier to
reason about how library code will behave when embedded in a page.

All the people I've spoken to about this in the WebKit community are fine
with changing WebKit once the behavior is clearly specced.

I don't have strong opinions about what path to take in the spec to achieve
this behavior.

This is why I think currently the specs support the Firefox/Safari/Chrome
> behaviour:
>
> * The ECMAScript spec says that the global environment (the one affected
>  by var statements in global code) is an object environment record
>  with its binding object being the global object.
>
>  http://people.mozilla.org/~**jorendorff/es5.html#sec-10.2.3<http://people.mozilla.org/~jorendorff/es5.html#sec-10.2.3>
>
> * Named properties are exposed on the window object through the
>  [[GetOwnProperty]] definition in Web IDL.
>
>  http://dev.w3.org/2006/webapi/**WebIDL/#getownproperty<http://dev.w3.org/2006/webapi/WebIDL/#getownproperty>
>
> * Since the Window interface has a getter but no setter, the descriptors
>  for the named properties are exposed as
>    { configurable: true, enumerable: true, writable: false, value: V }
>
> * There is no custom [[HasProperty]] defined in Web IDL, so when called
>  on the window object with the name of a named property it will return
>  true.
>
> * When the second <script> element in the document is run, the var
>  statement will be run as described in:
>
>  http://people.mozilla.org/~**jorendorff/es5.html#sec-10.5<http://people.mozilla.org/~jorendorff/es5.html#sec-10.5>
>
>  and in that algorithm we'll get to step 8.b, to determine whether a
>  variable binding for the name "a" already exists.  That step calls
>  the HasBinding operation for object environment records:
>
>  http://people.mozilla.org/~**jorendorff/es5.html#sec-10.2.**1.2.1<http://people.mozilla.org/~jorendorff/es5.html#sec-10.2.1.2.1>
>
>  which returns the result of [[HasProperty]], which in this case will
>  be true.  That'll mean step 8.c.i, which calls CreateMutableBinding,
>  is never run.
>
>
> Note that if the var statement has a variable assignment, such as in
>
>  <!DOCTYPE html>
>  <iframe name=a></iframe>
>  <script>
>    var a = 1;
>  </script>
>
> then the named property *will* be shadowed, due to the use of
> [ReplaceableNamedProperties] on the Window interface.  It's basically the
> same case as just having `a = 1;` as the script, due to the var declaration
> not having any effect.
>
>
> If we want var statements without a variable assignment to shadow named
> properties, then we can't keep [[GetOwnProperty]] returning property
> descriptors for them while [[HasProperty]] returns true for them, without
> violating the ECMAScript spec.
>
> We could either make [[HasProperty]] return false for named properties on
> window despite [[GetOwnProperty]] returning a property descriptor. Or, we
> could make the window object have a custom [[GetProperty]] instead of
> [[GetOwnProperty]], so that [[HasProperty]] returns false and
> [[GetOwnProperty]] returns undefined, while fetching the property off the
> object still gives you the named property value.
>
> So two questions:
>
> 1. Just to confirm, is having assignment-less var statements shadow
>   named properties the behaviour we want?
>
> 2. Is either of the above alternatives for achieving it preferable, or
>   is there another, better way I haven't thought of?
>
> Thanks,
>
> Cameron
>

Received on Wednesday, 4 January 2012 06:32:08 UTC