globalThis ECMAScript Proposal, specs, and reference implementation for global ( https://github.com/tc39/proposal-global )

Author

  • Jordan Harband

Rationale

It is difficult to write portable ECMAScript code which accesses the global object.

On the web, it is accessible as window or self or this or frames; on node.js, it is global or this; among those, only this is available in a shell like V8’s d8 or JavaScriptCore’s jsc.

In a standalone function call in sloppy mode, this works too, but it’s undefined in modules or in strict mode within a function.

In such contexts, the global object can still be accessed by Function(‘return this’)(), but that form is inaccessible with some CSP settings, such as within Chrome Apps.

Below is some code from the wild to get the global object, passed in as the single argument to an IIFE, which works for most cases but won’t actually work in d8 when in a module or in strict mode inside a function (which could be fixed using the Function trick):

 1 function foo() {
 2     // If we're in a browser, the global namespace is named 'window'. If we're
 3     // in node, it's named 'global'. If we're in a shell, 'this' might work.
 4     (typeof window !== "undefined"
 5         ? window
 6         : (typeof process === 'object' &&
 7            typeof require === 'function' &&
 8            typeof global === 'object')
 9             ? global
10             : this);
11 }

HTML and the WindowProxy

In HTML, the global object is separated into the Window and the WindowProxy.

New attributes are set on the Window, but top-level this has the identity of the WindowProxy.

The WindowProxy forwards all object operations to the underlying Window, but as the page changes, globalThis maintains the same identity while the underlying Window is swapped out.

The distinction is observable in the following scenario, with files parent.html, frame-a.html, and frame-b.html.

frame-a.html has the following source code:

<script>
  globalThis.foo = 'a';
  globalThis.getGlobalThis = () => globalThis;
</script>

frame-b.html has the following source code:

<script>
  globalThis.getGlobalThis = () => globalThis;
</script>

parent.html ’s source code is:

<iframe src="frame-a.html"></iframe>
<script>
  const iframe = document.querySelector('iframe');
  iframe.onload = () => {
    // The global variable `foo` exists.
    console.assert(frames[0].foo === 'a');
    const before = frames[0].getGlobalThis();
    iframe.onload = () => {
      // The global variable `foo` has disappeared.
      console.assert(frames[0].foo === undefined, 'The global object changes during navigation');
      const after = frames[0].getGlobalThis();
      // But, `globalThis` still has the same identity.
      console.assert(before === after, 'globalThis maintains its identity during navigation');
    };
    iframe.src = 'frame-b.html';
  };
</script>

This demo shows that the global variable foo was being stored on the actual global object, which has changed during navigation, but globalThis has not changed during navigation. Therefore, globalThis is not the global object.

Thus, globalThis is observably different from “the global object”, which is not directly accessible from JavaScript.

In web browsers, it’s even possible that (even in the global scope), foo !== globalThis.foo.

ES6/ES2015 does not account for the Window/WindowProxy structure, and simply refers to ”the global object” directly.

This specification does the same. If the ECMAScript specification is changed for top-level this to account for WindowProxy, then the change should also apply to the definition of this proposal.

Naming

There is desire to reify one of the existing global property names, particularly global or window, instead of System.global.

Further research will be done to determine if either of these two options will or will not break existing code doing runtime environment detection. Further research has determined that using global will not break existing code.

Attempts were made to ship under the name global, but it turns out that this does, in fact, break some existing websites.

After some data-gathering to determine web compatibility of a short list of choices, we settled on globalThis , as this name is both highly likely to be web compatible, and also maps to the concept of being the “global this value” (and not the “global object”, per above).

For a more detailed list of constraints, see NAMING.md.

globalThis

We live in a world where “universal” JavaScript is common.

This means that the same JavaScript code could be running on the client and on the server in NodeJS. This presents a particular set of challenges.

One is the global object, accessible from any piece of running code.

This is window in the browser, but global in Node. Writing universal code that accesses this global object relies on some conditional logic, that may look something like this (cover your eyes).

(typeof window !== "undefined"
? window
: (typeof process === 'object' &&
   typeof require === 'function' &&
   typeof global === 'object')
    ? global
    : this);

Thankfully, ES2020 brings with it the addition of the globalThis global variable. This will do the heavy lifting above for you and means you can now relax when it comes to accessing window or global in either front-end or back-end code.

globalThis.something = "Hello"; // Works in Browser and Node

globalThis ( https://v8.dev/features/globalthis )

For more details on why the above approach is insufficient (as well as an even more complicated technique), read a horrifying globalThis polyfill in universal JavaScript.

The globalThis proposal introduces a unified mechanism to access the global this in any JavaScript environment (browser, Node.js, or something else?), regardless of the script goal (classic script or module?).

const theGlobalThis = globalThis;

Note that modern code might not need access to the global this at all.

With JavaScript modules, you can declaratively import and export functionality instead of messing with global state.

globalThis is still useful for polyfills and other libraries that need global access.

Articles

https://javascript.info

https://www.freecodecamp.org

If you wrote some cross-platform JS code which could run on Node, in the browser environment, and also inside web-workers, you’d have a hard time getting hold of the global object.

This is because it is window for browsers, global for Node, and self for web workers. If there are more runtimes, the global object will be different for them as well.

So you would have had to have your own implementation of detecting runtime and then using the correct global – that is, until now.

ES2020 brings us globalThis which always refers to the global object, no matter where you are executing your code:

globalThis.setTimeout === window.setTimeout
true

https://www.jesuisundev.com

Le futur de Javascript est universel.

Ça veut dire qu’on devrait pouvoir prendre et utiliser du code fait sur Node et l’utiliser dans le navigateur (quand ça s’applique évidemment).

La plateforme ne devrait plus être un problème.

Mais aujourd’hui, c’est pas le cas.

Notamment au niveau des scopes et de comment accéder aux différentes valeurs. Par exemple dans la navigateur tu vas utiliser l’objet window pour accéder au global ‘ this ’.

En Node tu vas utiliser global. Etc etc.. Et du coup tu arrives à des solutions comme celle de Mathias Bynens sur son blog .

 1 // A naive attempt at getting the global `this`. Don’t use this!
 2 const getGlobalThis = () => {
 3   if (typeof globalThis !== 'undefined') return globalThis;
 4   if (typeof self !== 'undefined') return self;
 5   if (typeof window !== 'undefined') return window;
 6   if (typeof global !== 'undefined') return global;
 7   // Note: this might still return the wrong result!
 8   if (typeof this !== 'undefined') return this;
 9   throw new Error('Unable to locate global `this`');
10 };
11 const theGlobalThis = getGlobalThis();

Validé par l’ES2020, globalThis vient régler ce problème. C’est une façon simple et unifier d’accéder au global this pour toutes les plateformes. Fini les prises de têtes, tout le monde peut faire de la même façon désormais.

const theGlobalThis = globalThis;

https://exploringjs.com/impatient-js