globalThis
globalThis
” in “JavaScript for impatient programmers”.The ECMAScript proposal “globalThis
” by Jordan Harband provides a new standard way of accessing the global object.
JavaScript’s variable scopes are nested and form a tree whose root is the global scope. That scope is only the direct scope when a script runs in a web browser. There are two kinds of global variables:
const
, `let, and class declarations.var
and function declarations.The global object can be accessed via globalThis
. The following HTML fragment demonstrates globalThis
and the different kinds of global variables.
<script>
const one = 1;
var two = 2;
</script>
<script>
// All scripts share the same top-level scope:
console.log(one); // 1
console.log(two); // 2
// Not all declarations create properties of the global object:
console.log(globalThis.one); // undefined
console.log(globalThis.two); // 2
</script>
Note that each module has its own scope. Therefore, variables that exist at the top level of a module are not global. The following diagram illustrates how the various scopes are related.
this
Whenever there is no receiver (the object of a method call), the value of this
depends on the current scope:
undefined
undefined
this
If you call eval()
indirectly, it is executed in global scope, sloppily. Therefore, you can use the following code to get the global this
:
const theGlobalThis = eval.call(undefined, 'this');
new Function()
is also always evaluated in sloppy mode:
const theGlobalThis = new Function('return this')();
There is one important caveat, though: eval
, new Function()
, etc. are not available if you use CSP (Content Security Policy). That makes this approach unsuitable in many cases.
this
does not point directly to the global object As an example, consider an iframe on a web page:
src
of the iframe changes, it gets a new global object.this
always has the same value, which can be checked from outside the iframe, as demonstrated in the feature proposal.Browsers achieve that by distinguishing two objects:
Window
is the global object. It changes whenever the location changes.WindowProxy
is an object that forwards all accesses to the current Window
. This object never changes.In browsers, global this
refers to the WindowProxy
; everywhere else, it directly refers to the global object.
globalThis
and alternatives (window
, etc.) globalThis
is the new standard way of accessing global this
. Existing simple ways depend on the platform:
window
: is the classic way of referring to the global object. But it doesn’t work in Node.js and in Web Workers.self
: is available in Web Workers and browsers in general. But it isn’t supported by Node.js. Some people take self
appearing in code, as a sign that that code works in both Web Workers and normal browser settings.global
: is only available in Node.js.The proposal also standardizes that the global object must have Object.prototype
in its prototype chain. The following is already true in web browsers today:
> Object.prototype.isPrototypeOf(window)
true
globalThis
The global object is now considered a mistake that JavaScript can’t get rid of, due to backward compatibility. It affects performance negatively and is generally confusing.
ECMAScript introduced several features that make it easier to avoid the global object – for example:
const
, let
, and class declarations don’t create global object properties when used in global scope.It is normally preferable to refer to global variables as variables and not as properties of globalThis
. That has always worked on all JavaScript platforms.
Therefore, there are relatively few use cases for globalThis
– for example:
The proposal’s author, Jordan Harband, has written a polyfill for globalThis
.
Using it with CommonJS syntax:
// Computing the value of `global`
var global = require('globalthis')();
// Shimming `global` (installing it globally)
require('globalthis/shim')();
Using it with ES6 module syntax:
// Computing the value of `global`
import getGlobal from 'globalthis';
const global = getGlobal();
// Shimming `global` (installing it globally)
import shim from ‘globalthis/shim’; shim();
The package always uses the “most native” approach available (global
on Node.js etc., window
in normal browser contexts, etc.).
Internally, the polyfill uses the function getPolyfill()
to compute a reference to the global object. This is how that is achieved:
var implementation = require('./implementation');
module.exports = function getPolyfill() {
if (typeof global !== 'object' || !global
|| global.Math !== Math || global.Array !== Array) {
return implementation;
}
return global;
};
if (typeof self !== 'undefined') {
module.exports = self;
} else if (typeof window !== 'undefined') {
module.exports = window;
} else if (typeof global !== 'undefined') {
module.exports = global;
} else {
module.exports = Function('return this')();
}
globalThis
global
, self
, or window
everywhere? Alas, that is not possible, because many JavaScript libraries use these variables to detect which platform they are running on.
globalThis
were considered? An issue in the proposal’s repository lists names that were considered and why they were rejected.
General background:
this
value: “A horrifying globalThis
polyfill in universal JavaScript” by Mathias BynensSpecifications:
this
: “InitializeHostDefinedRealm()”