Search code examples
javascriptglobal

Is a Local Reference to the Global Scope Itself Fundamentally a Bad Idea?


Forgive my ignorance or paranoia if this is a stupid question, but I can't seem to find anything on this specific situation in particular (which leads me to think maybe most people either know to avoid it or have better ways to handle this).

Here's the premise: I don't know whether or not my code will necessarily always be ran in a browser, and as such, I don't know if I'll have access to window (specifically by that name) or if that scope will be named something else in whatever environment my code may find itself in.

So my idea was to find that scope once, assign it to a local variable then let everything within my function just reference that local variable if I ever need to access the global scope instead of reaching for window (again, it could be called something else—I won't know).

My concern is, is this going to cause some memory leak issue (or maybe it's a bad idea for other reasons)? Is there something I should be mindful of or am I good to go?

function myConstructor() {
    // Is this fundamentally a bad idea?
    var globalScope = findGlobalScope() // Cyclic reference here?

    function findGlobalScope() {
        // Let's say I had some logic here that
        // determinded that I'm running this code
        // in a browser, so now I know `window`
        // is where my global variables are.
        // Keep in mind it may not always be `window`,
        // but let's say this time it is.
        return window
    }

    this.doWork = function() {
        // In here I reference the `globalScope` variable
        // instead of the `window` variable explicitly.
        // 
        // I'm doing it this way because I don't want
        // my code to break if I run it outside of a browser
        // where I might not have access to an object explicitly
        // named "window"
        console.log(globalScope) // instead of console.log(window)
    }
}

var myObj = new myConstructor()

// Now `myObj` is located at `window.myObj`
// and `myObj` has a reference to `window`
// which... again, has a reference to window.myObj
// Is this something I should be concerned about?

I appreciate the help.


Solution

  • It's not a scope, it's an object. (But it's understandable you'd think of it as a scope; it's used by one of the global scopes to hold variables.¹)

    That's absolutely fine, it's not going to cause leaks or anything. That's one object that you know won't be going away (unless your code does, too).

    Note that JavaScript now has globalThis, which is exactly what you're looking for. :-) It's a relatively recent addition.


    That said, as Taplar mentioned, ideally your code shouldn't care about the global object, and should avoid creating global variables entirely if possible. The global namespace is crowded — and extremely crowded on browsers.

    Ways to avoid using global scope:

    1. Use modules. Modern environments support ES2015's modules. Older environments can be supported via bundlers like Webpack or Rollup.js.

    2. If you can't use a module, use a wrapper function. If necessary because your code must be split across files at runtime, have that function expose a single obscurely-named global that has properties on it for your other things.

    Example of #2 (using ES5 syntax):

    var myStuff = myStuff || {};
    (function() {
        myStuff.doSomething = function() {
           // ...
        };
    })();
    

    ¹ This is an interesting, but confusing, part of JavaScript: There are at least two global scopes in JavaScript, and outer one and an inner one (which is new in ES2015+).

    The outer one has "variables" that are properties of the global object, either inherited ones or own properties: If you use a variable name, and it doesn't exist in the current scope or one between the current scope and the global scope, but does exist as a property on the global object, the property on the global object is used — an old-style global variable. When you declare a function at global scope, or declare a variable with var, it adds a property to the global object. The global object also (in most environments) inherits things from its prototype and its prototype's prototype. For instance, globals created on browsers for elements with an id are properties of the WindowProperties object, which is in the prototype chain of the global object. It also sometimes has other "own" properties, such as name (the name of the window on browsers).

    The inner global scope doesn't use the global object. It's where things declared with let, const, and class go. They don't become properties of the global object.