84

I want to check in a script if a certain other module is already loaded.

if (ModuleName) {
    // extend this module
}

But if ModuleName doesn't exist, that throws.

If I knew what the Global Object was I could use that.

if (window.ModuleName) {
    // extend this module
}

But since I want my module to work with both browsers and node, rhino, etc., I can't assume window.

As I understand it, this doesn't work in ES 5 with "use strict";

var MyGLOBAL = (function () {return this;}()); // MyGlobal becomes null

This will also fail with a thrown exception

var MyGLOBAL = window || GLOBAL

So it seems like I'm left with

try {
    // Extend ModuleName
} 
catch(ignore) {
}

None of these cases will pass JSLint.

Am I missing anything?

Qantas 94 Heavy
  • 15,750
  • 31
  • 68
  • 83
coolaj86
  • 74,004
  • 20
  • 105
  • 125
  • Note that "var Fn = Function, global = Fn('return this')();" will *not* pass JSLint, since JSLint expects functions with a capital letter to be a constructor and to be called with 'new'. It's a simple fix, though. – user4815162342 Oct 10 '12 at 22:26
  • This also passes JSLint, and it doesn't require an extra `Fn` variable: `var global = (function (fn) { return fn('return this'); }(Function));` – ahuth May 23 '13 at 12:25
  • @ahuth You need an extra `()` in there. – wizzwizz4 Jul 17 '16 at 12:59
  • You can get the global object like this (without eval or Function constructor): `var global = (function(){return this}).apply(null)`. More infos at https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply – mems Sep 06 '17 at 09:22
  • 1
    Note: apply(null) doesn't give the global object if you are using the strict mode: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode#Securing_JavaScript – mems Sep 06 '17 at 09:33
  • Yes it gives a null object. :( – Aero Wang Apr 02 '19 at 02:29

10 Answers10

101

Well, you can use the typeof operator, and if the identifier doesn't exist in any place of the scope chain, it will not throw a ReferenceError, it will just return "undefined":

if (typeof ModuleName != 'undefined') {
  //...
}

Remember also that the this value on Global code, refers to the global object, meaning that if your if statement is on the global context, you can simply check this.ModuleName.

About the (function () { return this; }()); technique, you are right, on strict mode the this value will simply be undefined.

Under strict mode there are two ways to get a reference to the Global object, no matter where you are:

  • Through the Function constructor:

    var global = Function('return this')();
    

Functions created with the Function constructor don't inherit the strictness of the caller, they are strict only if they start their body with the 'use strict' directive, otherwise they are non-strict.

This method is compatible with any ES3 implementation.

  • Through an indirect eval call, for example:

    "use strict";
    var get = eval;
    var global = get("this");
    

The above will work because in ES5, indirect calls to eval, use the global environment as both, the variable environment and lexical environment for the eval code.

See details on Entering Eval Code, Step 1.

But be aware that the last solution will not work on ES3 implementations, because an indirect call to eval on ES3 will use the variable and lexical environments of the caller as the environments for the eval code itself.

And at last, you may find useful to detect if strict mode is supported:

var isStrictSupported = (function () { "use strict"; return !this; })();
Christian C. Salvadó
  • 807,428
  • 183
  • 922
  • 838
  • 5
    +1 @CMS - I've lost count of how many times I've read your answers on this site. Thanks man. – screenm0nkey Aug 04 '11 at 12:36
  • 1
    Possibly obvious question: Why use "use strict" and then circumvent one of its effects? Is there a reason that the only way to get the global context is a bit hacky? – mowwwalker Feb 11 '13 at 03:17
  • 1
    @Walkerneo one reason could be that we're really not supposed to be adding anything to the global scope (although it can be useful, like when we need to export a library API). Also, I believe that the use of "this" is restricted (in strict mode) because it may not always be obvious what this refers to. Achieving that makes it difficult to get a reference to the global object. – ahuth May 23 '13 at 12:28
  • 4
    Sadly, Function('return this') does not work. In Chrome I am getting: EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'unsafe-inline'". – Pat Sep 23 '14 at 19:59
  • 1
    @CMS Notice that `Function` can be overriden or even shadowed in a child scope. It is better to use `var global = (() => {}).constructor('return this')();` –  Aug 27 '16 at 16:28
  • With arrow function and strict mode support, you can use `"use strict";var global = ($=>this)();//Window` – mems Sep 08 '17 at 08:28
  • @mowwwalker In ES6+ classes and modules, strict mode is enforced by default, so you may have no choice but to be in strict mode, therefore this can come in handy. :) – trusktr Apr 10 '18 at 01:37
27

Update 2019

With all of today's Webpacks and Broccolis, and Gulps and Grunts, and TypeScripts and AltScripts, and create-react-apps, etc, this is pretty useless, but if you're just working with plain, old, VanillaJS and you want to make it isomorphic, this is probably your best option:

var global
try {
  global = Function('return this')();
} catch(e) {
  global = window;
}

The Function constructor invocation will work even when using --use_strict in node, as the Function constructor always executes in a global non-strict scope.

If the Function constructor fails, it's because you're in a browser with eval disabled by CSP headers.

Of course, with Deno on the way (the node replacement), they may also disallow the Function constructor, in which case it's back to enumerating objects like global, module, exports, globalThis and window, and then duck-type checking which is the global exhaustively... :-/

Crazy one-line solution (Original):

var global = Function('return this')() || (42, eval)('this');

.

.

.

Works

  • in every environment (that I tested)
  • in strict mode
  • and even in a nested scope

Update 2014-Sept-23

This can now fail if HTTP headers in the latest browsers explicitly forbid eval.

A workaround would be to try / catch the original solution as only browsers are known to run this type of subset of JavaScript.

var global;

try {
  global = Function('return this')() || (42, eval)('this');
} catch(e) {
  global = window;
}
Example:
---

    (function () {

      var global = Function('return this')() || (42, eval)('this');
      console.log(global);

      // es3 context is `global`, es5 is `null`
      (function () {
        "use strict";

        var global = Function('return this')() || (42, eval)('this');
        console.log(global);

      }());

      // es3 and es5 context is 'someNewContext'
      (function () {

        var global = Function('return this')() || (42, eval)('this');
        console.log(global);

      }).call('someNewContext');

    }());

Tested:
---

  * Chrome v12
  * Node.JS v0.4.9
  * Firefox v5
  * MSIE 8

Why:
---

In short: it's some weird quirk. See the comments below (or the post above)


In `strict mode` `this` is never the global, but also in `strict mode` `eval` operates in a separate context in which `this` *is* always the global.

In non-strict mode `this` is the current context. If there is no current context, it assumes the global. An anonymous function has no context and hence in non-strict mode assumes the global.

Sub Rant:

There's a silly misfeature of JavaScript that 99.9% of the time just confuses people called the 'comma operator'.

    var a = 0, b = 1;
    a = 0, 1;          // 1
    (a = 0), 1;        // 1
    a = (0, 1);        // 1
    a = (42, eval);    // eval
    a('this');         // the global object
coolaj86
  • 74,004
  • 20
  • 105
  • 125
  • 1
    This is not just a weird quirk, it's what I described in my answer as an *indirect call to `eval`*. In ES5, a call to `eval` is in direct *only* if the [`CallExpression`](http://j.mp/ostl7R) is formed by a `MemberExpression` that meets two conditions: 1. The base value of the reference is an environment record. 2. The reference name is `"eval"`, any other way to invoke `eval` will result in an indirect call. Be careful since this behavior will not work in ES3, since the concept of *direct calls* to eval didn't existed. Try [this example](http://j.mp/nqknGX) with a ES3 implementation (e.g. IE8) – Christian C. Salvadó Aug 04 '11 at 13:49
  • 3
    @CoolAJ86, your new code will work also on ES3 implementations, but if you examine it carefully, you will notice that the indirect `eval` part isn't necessary at all, all you need is `var global = Function('return this')();`, as I described, "Functions created with the `Function` constructor don't inherit the strictness of the caller", meaning that the return value of that function, will be *always* the global object, -regardless the implementation-. The `eval` call at the right side of the `||` operator, will never be made, since the function will always yield a truthy value (the global obj). – Christian C. Salvadó Aug 04 '11 at 18:31
  • 1
    You may be adding to the comma confusion by stating `a = 0, 1; // 0` and `(a = 0), 1; // 0` as both expressions return `1`. Perhaps `// a = 0` would be better. – MikeM Jan 04 '13 at 18:08
  • Hmm... I could have sworn when I was testing it I got 0... but you're definitely right. updated the anwser – coolaj86 Jan 05 '13 at 18:24
  • When will the expression `(42, eval)('this')` be evaluated? In other words, when will `Function('return this')()` be false? – zVictor Apr 11 '13 at 17:02
  • Is there a way to make (42, eval)('this') pass JSLint? – ahuth May 23 '13 at 12:31
  • Sadly this can STILL fail: In chrome, I am getting this error :::: EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'unsafe-inline'". – Pat Sep 23 '14 at 19:56
  • I didn't realize the HTTP headers could enforce javascript parsing rules. How do you get around it there? – coolaj86 Sep 23 '14 at 20:25
  • @zVictor asked "In other words, when will `Function('return this')()` be false?" Will `(42, eval)( 'this' )` ever be evaluated in some engine? Is not the `Function` version enough? – trusktr Apr 10 '18 at 02:16
  • 1
    @CoolAJ86, What's wrong with just using `eval('this')` instead of `(x, eval)('this')` – Pacerier May 28 '19 at 17:13
  • 1
    @Pacerier there's a difference in how a direct vs indirect call to eval evaluates it's context. – coolaj86 May 29 '19 at 17:35
5

Why just don't simply use this in a global scope as param to a wrapper function, as follows?

(function (global) {
    'use strict';
    // Code
}(this));
  • 2
    Surprising that nobody pointed out yet that this doesn't really add anything that Szabolcs Kurdi's answer didn't already provide a year earlier. It doesn't address the issue raised in the comments there, which is that it *needs* to be called in global scope in order to work, but at least your answer does acknowledge that. –  Apr 09 '16 at 21:20
  • This does not work in a NodeJS module, where `this === module.exports`. – lapo Jul 18 '20 at 12:47
4

Here you go :)

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

This should work from anywhere, for example from within another closure.

Edit - just read your post more carefully and saw the part about ES5 strict mode. Can anyone shed some more light on that? This has been the accepted way to get the the global object for as long as I can remember... I sure hope it doesn't end up getting broken.

Edit 2 - CMS' answer has more info on ES5 strict mode's treatment of this.

Dagg Nabbit
  • 75,346
  • 19
  • 113
  • 141
3

I think this is pretty much okay in rhino, node, browser and with jslint (without additional workaround flags) - would this help? Am I missing something?

x = 1;
(function(global){
    "use strict";
    console.log(global.x);
}(this));

Though I myself tend to use the window object and if I do need headless testing I can use env.js (rhino) or Phantom (node).

  • It passes jslint without additional options (if you strip the x=1 example), though it's just an alternative I guess (while being elegant is a highly subjective factor). –  Oct 04 '12 at 13:19
  • 2
    You're missing the fact that `this` might not refer to the global object. – MikeM Jan 04 '13 at 18:15
  • As far as I know it does refer to the global scope if used in the global scope (browser, rhino, node), but I may be wrong. Can you show an example vm where it works differently? Thanks! –  Jan 07 '13 at 11:27
  • 1
    @SzabolcsKurdi You're right that 'this' will be the global scope when used in the global scope. The problem is that there's no guarantee that the function will be executed in the global scope. For instance, if this get's put in a library and wrapped in an immediately invoked function. What we're really looking for is a way to get the global scope __regardless__ of the scope it's called in. – ahuth May 23 '13 at 12:33
3

ECMAScript will be adding this to its standard soon: https://github.com/tc39/proposal-global

Until its done, this is what's recommended:

var getGlobal = function () {
    // the only reliable means to get the global object is
    // `Function('return this')()`
    // However, this causes CSP violations in Chrome apps.
    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');
};
Shaun Lebron
  • 2,501
  • 28
  • 29
  • [This](https://bugzilla.mozilla.org/show_bug.cgi?id=1328218) is problematic; all versions prior 2.9 are affected and Moment is a very popular library. – Knu Oct 05 '18 at 10:13
1

This is not passing jslint: var Fn = Function, global = Fn('return this')();

Try it yourself: http://www.jslint.com/

this will: var Fn = Function, global = new Fn('return this')();

But effectively those are same thing according to MDN:

Invoking the Function constructor as a function (without using the new operator) has the same effect as invoking it as a constructor.

senz
  • 1,980
  • 1
  • 16
  • 14
1

This following solution works in:

  • Chrome
  • Node.JS
  • Firefox
  • MSIE
  • Web Workers

The code is:

(function (__global) {
  // __global here points to the global object
})(typeof window !== "undefined" ? window : 
   typeof WorkerGlobalScope !== "undefined" ? self :
   typeof global !== "undefined" ? global :
   Function("return this;")());

You just need to change X for the name of the variable that you would like to

Remo H. Jansen
  • 23,172
  • 11
  • 70
  • 93
0

Here's what I am using:

"use strict";
if(this && this.hasOwnProperty && !this.hasOwnProperty('globalScope')){
    try {
        globalScope = Function('return this')();
    }catch(ex){
        if(this.hasOwnProperty('window')){
            globalScope = window;
        }else{
            throw 'globalScope not found';
        }
    }
}
Lorenz Lo Sauer
  • 23,698
  • 16
  • 85
  • 87
0

I had this problem before, I'm not happy with the solution, but it works and passes JSLint (assume browser|assume node):

"use strict";
var GLOBAL;
try{
    /*BROWSER*/
    GLOBAL = window;
}catch(e){
    /*NODE*/
    GLOBAL = global;
}
if(GLOBAL.GLOBAL !== GLOBAL){
    throw new Error("library cannot find the global object");
}

once you have the GLOBAL var you can do your checking, and at the end of the script type

delete GLOBAL.GLOBAL;
Andro Selva
  • 53,910
  • 52
  • 193
  • 240
  • I confirm that this approach is clean and useful. Not sure why it is not upvoted more compared to all the evil solutions in other answers. –  Dec 17 '16 at 21:33