variable declarations shadowing named properties on window

In 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) 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"

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

* Named properties are exposed on the window object through the
   [[GetOwnProperty]] definition in Web IDL.

   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

   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

   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 00:55:05 UTC