Dagg Nabbit
Dagg Nabbit

Reputation: 76756

Getting a reference to the global object in an unknown environment in strict mode

What is the recommended way to get a handle to the global object in ES5 strict mode in an unknown host environment?

ECMAScript doesn't provide a built-in way to reference the global object that I'm aware of. If it does, this is the answer I'm looking for.

In a known environment, the global object usually has a self-referential property. Since the global object is the VO for the global scope, properties of the global object are global variables, so we can use them get a handle to the global object from anywhere:

However, this is not necessarily the case in all host environments. As far as I know, Windows Script Host does not provide any way to access the global object. The recommended way to get the global object in WSH seems to be to use the this keyword in a context where it does not resolve to an object. For example:

var GLOBAL = (function(){return this}());

This technique will work for any host environment, but not in strict mode, because an undefined this does not reference the global object in strict mode:

If this is evaluated within strict mode code, then the this value is not coerced to an object. A this value of null or undefined is not converted to the global object and primitive values are not converted to wrapper objects. The this value passed via a function call (including calls made using Function.prototype.apply and Function.prototype.call) do not coerce the passed this value to an object (10.4.3, 11.1.1, 15.3.4.3, 15.3.4.4).

As expected, the following code results in undefined:

(function(){
    "use strict";
    var GLOBAL = (function(){return this}());
    console.log(GLOBAL);
}());

So, what is the proper way to get a handle to the global object in any environment, regardless of strict mode?

By the way, my current approach is to sniff for global variables referencing the global object like this:

var self, window, global = global || window || self;

...and then just use global. I think this is a bad solution for a number of reasons, most of which are fairly obvious, and it doesn't address the WSH problem.

Upvotes: 21

Views: 7271

Answers (4)

Kithraya
Kithraya

Reputation: 398

Mathias Bynens has an excellent article on the subject. The following works in all environments, use strict or no, including ones with CSP enabled, like Chrome extensions.

(function() {

    // A globalThis polyfill | # | Adapted from https://mathiasbynens.be/notes/globalthis

    if (typeof window !== 'undefined' && window && window.window === window) { return window } // all browsers
    else { // webworkers, or server-side Javascript, like Node.js
        try {
            Object.defineProperty( Object.prototype, '__magic__', { // hocus pocus
                get: function() {
                    return this;
                },
                configurable: true // This makes it possible to 'delete' the getter later
            });
            __magic__.globalThis = __magic__;
            delete Object.prototype.__magic__;

            return globalThis;
        } catch (e) {
            // we shouldn't ever get here, since all server-side JS environments that I know of support Object.defineProperty
            return (typeof globalThis === 'object') ? globalThis : ( (typeof global === 'object') ? global : this );
        }
    }
})();

Upvotes: 0

Bergi
Bergi

Reputation: 664920

In global code, the thisBinding is set to the global object regardless of strict mode. That means you can pass it from there into your module IEFE:

// "use strict"; or not
(function(global) {
    "use strict";
    …
    console.log(global);
    …
}(this));

Upvotes: 7

kangax
kangax

Reputation: 39188

In ES5, you can get a reference to global object from within strict mode via indirect eval call:

"use strict";
var global = (1,eval)('this');

Take a look at my article; particularly at this section on strict mode.

Upvotes: 29

user1207456
user1207456

Reputation:

In strict mode, the way to get a reference to the global object is to assign a variable in the global object referencing itself.

That is this means the global object when in the global context, so the solution is simply:

"use strict";
var global = global || this;
(function() { global.hello = "world"; })();
console.log(hello); // Outputs 'world' as expected

This does mean that you have to pollute the global namespace with a reference to itself, but like you say, it should already have been there.

Upvotes: 1

Related Questions