35

It's considered good practice to use a self-invoking function to wrap strict mode compliant code, often called the strict mode pragma:

(function(){
  "use strict";
  // Strict code here
}());

My question is how to declare global variables in this case? Three alternatives that I know of today:

Alternative 1:

var GLOB = {};

(function(){
  "use strict";
}());

Alternative 2:

(function(){
  "use strict";
  window.GLOB = {};
}());

Alternative 3:

(function(win){
  "use strict";
  win.GLOB = {};
}(window));

Any preferences and motivations? Other options?

Larry K
  • 47,808
  • 15
  • 87
  • 140
johnwilander
  • 526
  • 1
  • 4
  • 6

5 Answers5

57

IMO alternative 3 is best. But it assumes that window represents the global scope - which is true for the browser but not for other JS environments (command line, Node.js, etc.).

The following will work across the board:

(function(globals){
  "use strict";
  globals.GLOB = {};
}(this));
Stepan Riha
  • 1,736
  • 14
  • 12
  • 1
    if this===undefined this will not define a global, Adassko answer below is better – kofifus Sep 11 '16 at 23:56
  • Using `eval` has some overhead associated with it. In my code, I reserve it for situation where a I know I need it. In the common scenario where you isolate the entire contents of a script file in a SEAF, `this` will point at the global scope. See the [various UMD wrappers](https://github.com/umdjs/umd) for common usage. – Stepan Riha Sep 29 '16 at 15:02
11

I know this is an old question but there's one not mentioned way of getting global context:

(function(globals){
  "use strict";
  globals.GLOB = {};
}( (1,eval)('this') ));

(1,eval)('this')

will evaluate this from global context, so you can paste this wherever you like and you will always get global context

Adassko
  • 5,201
  • 20
  • 37
1

Method 1 would fail if it's pasted in another function.

Using method 3, it is easier to export your methods to another namespace. Simply replacing window with, say, frames[0] or document is enough to attach all methods to a custom namespace.

I recommend method 3, for the last reason.

Rob W
  • 341,306
  • 83
  • 791
  • 678
1

Benefit of alt 2 and 3 is that they keep all of the code inside the "container function." One line of code outside of the function is easy to miss when reading the code.

Also:

  • "GLOB" should be the application's name. -- You want to allow for more than one application per html/js file without name collisions.
Larry K
  • 47,808
  • 15
  • 87
  • 140
  • I only used GLOB as a placeholder for whatever namespace or global I'd be creating. Agree the wrapping closure should cover the whole file for the pragma to make sense. – johnwilander Feb 22 '12 at 16:03
0

Andrea Giammarchi has a nice technique for doing this, that works across browsers. Define a function in your self-invoking function called globalEval like so:

(function () {
    "use strict";
    function globalEval(data) {
        data = data.replace(/^\s*|\s*$/g, "");
        if (data) {
            var head = document.getElementsByTagName("head")[0] || document.documentElement,
                script = document.createElement("script");
            script.type = "text/javascript";
            script.text = data;
            head.appendChild(script);
            head.removeChild(script);
        }
    }

    // use globalEval to stick variables into the global scope
    globalEval("var myGlobal = 1;");
    // myGlobal === 1
)();
// myGlobal === 1

Or define the globalEval function outside of the self-invoking code if you want to use it in other scopes.

DaveS
  • 3,156
  • 1
  • 21
  • 31
  • The question is how to declare global variables from within a self-contained scope, no? – DaveS Feb 22 '12 at 15:54
  • 1
    Given the examples, the OP wants to know which of these methods is the best for exporting known variables to the global scope. Your answer *does* explain how to define global variables. However, it's a very expensive way to define `GLOB={};`. – Rob W Feb 22 '12 at 16:00
  • It could be considered a fourth option but as Rob says it's a little bit heavy and will also taint my with loads of small script tags. It should be noted that globalEval() is a general "execute anything inside a script tag" function and not just a "declare globals" function. – johnwilander Feb 22 '12 at 16:07
  • Given the examples, yes...but the question also asks for other options. This is a more flexible option. It's great, for example, if you need to execute code sent by the server as a string. But it also works for simple variable declaration at the global scope. – DaveS Feb 22 '12 at 16:07
  • The script cleans up after itself. It doesn't leave script tags in the head. – DaveS Feb 22 '12 at 16:08