Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the global object in JavaScript?

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?

like image 599
coolaj86 Avatar asked Jul 18 '10 20:07

coolaj86


People also ask

How do you access global objects?

The global object in JavaScript is an always defined object that provides variables and functions, and is available anywhere. In a web browser, the global object is the window object, while it is named global in Node. js. The global object can be accessed using the this operator in the global scope.

What is the global object in JavaScript?

A global object is an object that always exists in the global scope. In JavaScript, there's always a global object defined. In a web browser, when scripts create global variables defined with the var keyword, they're created as members of the global object. (In Node.

Where are global variables stored in JavaScript?

Are global variables stored in specific object? The answer is yes; they are stored in something called, officially, the global object. This object is described in Section 15.1 of the official ECMAScript 5 Specification.


2 Answers

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; })(); 
like image 172
Christian C. Salvadó Avatar answered Oct 14 '22 20:10

Christian C. Salvadó


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 
like image 29
coolaj86 Avatar answered Oct 14 '22 21:10

coolaj86