Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use core-js for getGlobals example #17337

Merged
merged 5 commits into from
Aug 25, 2022
Merged
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,28 +38,59 @@ Several other popular name choices such as `self` and `global` were removed from

### Search for the global across environments

Prior to `globalThis`, the only reliable cross-platform way to get the global object for an environment was `Function('return this')()`. However, this causes [CSP](/en-US/docs/Web/HTTP/CSP) violations in some settings, so [es6-shim](https://github.com/paulmillr/es6-shim) uses a check like this, for example:
Usually, the global object does not need to be explicitly specified — its properties are automatically accessible as global variables.

```js
const getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
console.log(window.NaN === NaN); // true
```

However, one case where one needs to explicitly access the global object is when _writing_ to it, usually for the purpose of [polyfills](/en-US/docs/Glossary/Polyfill).

Prior to `globalThis`, the only reliable cross-platform way to get the global object for an environment was `Function('return this')()`. However, this causes [CSP](/en-US/docs/Web/HTTP/CSP) violations in some settings, so [core-js](https://github.com/zloirock/core-js/blob/master/packages/core-js/internals/global.js) uses a piecewise definition like this, for example (slightly modified from the original source):
Josh-Cena marked this conversation as resolved.
Show resolved Hide resolved

const globals = getGlobal();
```js
function check(it) {
// Math is known to exist as a global in every environment.
return it && it.Math === Math && it;
}

if (typeof globals.setTimeout !== 'function') {
// no setTimeout in this environment!
const globalObject =
check(typeof window === 'object' && window) ||
check(typeof self === 'object' && self) ||
check(typeof global === 'object' && global) ||
// This returns undefined when running in strict mode
(function () { return this; })() ||
Function('return this')();
Copy link
Contributor

@zloirock zloirock Aug 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now, without globalThis, it will not work in cases of ES-only environments (no one of the variables above) in modules context (IIFE this is undefined), where for security reasons disabled evaluation via eval / Function. It's not a big problem to create such an environment, for example, with NodeJS vm.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right—the purpose of this example is to illustrate what happens without globalThis. I did dig into the history of internals/global.js and it was something like this a long time ago: https://github.com/zloirock/core-js/blob/b4e8c0b09bbe23db8d8784df03ef0b8f3ff04170/packages/core-js/internals/global.js

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And after that, someone wrote me an issue about such an environment.

Someone could try to use the code from this example as a universal way of getting the global object and theoretically, it could fail in this specific and rare case. So I think changing "prior to globalThis ..." to something else could be better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only thing I've modified from the core-JS source is removal of the globalThis mention. In a runtime without globalThis, is there anything better than this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean that someone could try this code everywhere as something universal - in environments without globalThis and in environments with.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh well, it was kind of the same code before—let's hope no one uses it as a polyfill (they shouldn't!) If you want to add a warning box making it explicit, feel free to.

```

After obtaining the global object, we can define new globals on it. For example, adding an implementation for [`Intl`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl):

```js
if (typeof globalObject.Intl === 'undefined') {
// No Intl in this environment; define our own on the global scope
Object.defineProperty(globalObject, 'Intl', {
value: {
// Our Intl implementation
},
enumerable: false,
configurable: true,
writable: true,
});
}
```

With `globalThis` available, the additional search for the global across environments is not necessary anymore:

```js
if (typeof globalThis.setTimeout !== 'function') {
// no setTimeout in this environment!
if (typeof globalThis.Intl === 'undefined') {
Object.defineProperty(globalThis, 'Intl', {
value: {
// Our Intl implementation
},
enumerable: false,
configurable: true,
writable: true,
});
}
```

Expand Down