The global object as the "global scope instance object"

Allen Wirfs-Brock allen at
Fri Jan 20 16:23:33 PST 2012

On Jan 20, 2012, at 5:55 AM, Andreas Rossberg wrote:

> From the TC39 notes:
>> DaveH:  What if there are duplicate top-level bindings?
>> MarkM:  Top-level let should behave as much as possible the same as
>> concatenated scripts.
> It's my claim that it is impossible to reconcile all of the following
> three goals in a way that is even remotely sane:
> 1. Top-level bindings are aliased as data properties of the global object.
> 2. Top-level bindings allow redefinition of existing properties of the
> global object.

the rules are more complex than this. see There are important distinctions between own and inherited properties of the global object and properties created using var/function declarations (all we have in ES5) and arbitrary properties directly created by the user or host.

> 3. Top-level let/const have a temporal dead-zone.
> Abandoning (3) essentially means abandoning a reasonable "const"
> semantics for the toplevel (and future hostile to guards), so we don't
> want to do that. (For V8, we had long struggles with defining and
> implementing a const for the (current notion of) top-level that
> actually makes any sense. We failed.)

Temporal dead-zone initialization tracking requires extra state and checking (except for the common cases within functions where it can be statically determined that there are no possible references within the dead zone).  This additional requirement is reflected in the specification in the ES5 definition of the CreateImmutableBinding and InitializeImmutableBinding environment record methods.  In ES5 this mechanism (and state) was only needed within DeclarativeEnviornmentRecords for (the rarely used) immutable bindings. For the ES6 spec. this has been generalize to also apply to ObjectEnvironmentRecords and to track initialization of both mutable and immutable bindings.  

The specification doesn't address how an implementation might represent that state but it needs to be somewhere. Closure capturing the state in getter/setter functions may be one way to do this for the global scope.  I imagine that there are other ways.  For example, global object properties could potentially have an implementation specific "not yet initialized" bit associated with properties on the global object.  Or you might "shadow" the entire global object with a special kind of environment record that that censors access to instantiated but initialized global bindings (add entry to the censor environment when the binding is instantiated, only create a property in the global object when it is initialized).

However, I agree that there are still significant issues with rationally integrating the semantics of global object property access semantics and the ES global declaration semantics.  Both for ES5 and ES6.

> Hence, I would like to suggest another, more moderate idea for a
> global scope reform: treat the global object similar to a module
> instance objects. That is:
> - Top-level bindings (other than var) are reflected as accessor
> properties on the global object.
> - They are defined on the global object before the script starts executing.
> - Their getters/setters simply delegate to the bound variables.

whose access presumably perform the necessary checks to enforce the temporal deadzone. 

> - For const bindings, there are no setters.
> - These properties are non-configurable.

It is already the case (for ES5) that all properties created for global declarations are non-configurable (unless created by an eval).

> - Unlike a module instance object, the global object is extensible
> (multiple scripts!).
> This disallows lexical bindings to redefine existing non-configurable
> properties of the global object (including ones reflecting bindings
> from earlier scripts), which is checked before the script starts
> executing. Likewise, let/const-defined properties cannot later be
> deleted from the global object.

I'm not yet convinced that you need to publicly expose such global object properties accessor properties.  I think it is possible to hide the mechanisms.

> Apart from that, not much should change in practical terms. You should
> pretty much be able to replace var with let. At the same time, static
> scoping actually is maintained, and there is no issue with temporal
> dead zones. Moreover, concatenating scripts would not affect the
> meaning or validity of bindings, AFAICS.

Independent of implementation schemes, I think we need to decide on the meaning of the following independent scripts (in different documents)

"do not use strict";
// does not exist at this point.
foo = 10
const foo=5;  //or let

// does not exist at this point. = 10
const foo=5;  //or let

// does not exist at this point.
const foo=5;  //or let


> Regarding scope pollution, I think this is best solved by making the
> global object be a fresh empty object that has the object containing
> all primordials as its prototype. Overriding is allowed according to
> the standard defineProperty semantics. No special rules necessary.

In that case, why is it an object at all?  Why not simply a DeclarativeEnvironmentRecord in an environment whose outer is a GlobalEnvironmentRecord whose backing object is the global object?  I'm actually think along some similar lines but I think this direction raises interesting questions, going forward,  about about some current fundamental assumptions:

What is the role of the global object?
Must all ES global declarations reify as properties on the global object?
If not, which global declarations must reify as such?  (what are the actual web dependencies).
Must all built-in globally accessible bindings reify as global object properties?

I have some ideas.  I'll see if they hold together as I try to fill them out.


> /Andreas
> _______________________________________________
> es-discuss mailing list
> es-discuss at

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list