Is JavaScript’s “Global” Scope Really Just A Closure?

I hear a lot of talk about how it’s a performance penalty to use globally scoped variables in JavaScript (not to mention, dangerous / dumb). When a function looks for a variable, it checks the current scope, then it checks any outer scopes that the function may be nested in, and finally it reaches the outer-most scope: the global scope of the JavaScript runtime.

It occurred to me, as I was wrapping up the edits for my “Variable Scope In JavaScript” screencast, that this is evidence to suggest that access to the global scope, from anywhere other than the global scope in a JavaScript runtime environment, is nothing more than a closure.

Look at it this way: when we access the “foo” variable from within the “sayFoo” function of this code

(click the link for the JSFiddle, if you’re in an RSS reader) the runtime has to step out of the “sayFoo” function and find the “foo” variable declared in the “outerScope” function.

Now look at similar code accessing the `$` variable from jQuery, as well as a `bar` variable defined in the outermost, global scope:

Honestly, I had always assumed that there was something special about the global scope of a JavaScript runtime. I had assumed that the browsers and other runtimes had to build some special mechanism in which the global scope was made available to other scopes. It looks like global scope is nothing more than the bi-product of the closure support that JavaScript has built into it, in combination with the outermost scope of the runtime (a DOMWindow or some other scope for CommonJS implementations).

… mystery, suddenly not so mysterious.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in Javascript. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Julian Birch

    You can’t add a new variable to a closure, though. I suspect this has an impact.

    • http://mutedsolutions.com Derick Bailey

      true – it would be easy enough to add an undeclared var to the global scope and then when it’s accessed, it would be through a closure. so that’s probably one “rule” or special case to make this work.

    • http://mutedsolutions.com Derick Bailey

      this popped into my head a moment ago:

      when a variable is accessed, whether or read or assignment, the runtime has to find the location of that variable. it first checks the local scope. if not found, it moved up to the next outer scope. if not found, it moves up again, until it finally reaches the global scope.

      at any point in time, if the variable declaration is found in the scope that is currently being examined, the runtime uses that variable.

      it would make sense that this same basic process works for both reads and writes, with one small exception:

      when reading a variable, the runtime will reach the top of the global scope and if not found, it will throw an error saying the variable is not defined. 

      but when assigning something to a variable, when the runtime reaches the very top of the global scope and doesn’t find any declaration for the variable, the runtime shrugs and says “whatever. i’ll just create a variable for you, here”.

      so… it makes sense in my head, then, that you actually can create a variable in a scope outside of your current scope… but the only scope where this ever happens is the global scope, because the runtime just keeps searching up the scope stack until it either finds the declaration, or reaches the top.

      … at least, that’s how I would do it if i were building JavaScript. it’s the simplest way to make this work, in my head. though I’m sure there are many nuances, subtleties, and other cases that my simple line of thinking hasn’t covered. :)

  • http://attack.io Jason Mulligan

    global scope is not a closure, it’s a shorthand to window; everything ends up on window.

    • http://josephvano.wordpress.com/ Joey Vano

      In a browser environment, yes.

      • http://attack.io Jason Mulligan

        True, but the context of the copy appears to be a browser so it’s a safe assumption.

        • Avi Block

          Really…

          “It looks like global scope is nothing more than the bi-product of the closure support that JavaScript has built into it, in combination with the outermost scope of the runtime (a DOMWindow or some other scope for CommonJS implementations).”

  • http://twitter.com/developingchris developingchris

    I find it interesting too, if you think of the dom as being all inside a self run function like this.

    new function (){  var window = this;   // running before the html tag. and the closing brace  
    <html>
    </html>
    }

    Then now you can see, there is no global scope, just everything as a closure scoped to window.

  • http://www.webhostings.in website hosting india

    I follow above the steps to implement global variable in java script.Most of the points are explained very clearly.

  • Jason Sebring

    Apparently NOT. I would think the same but WTF is this example I cooked up. It defies my understanding. Please help.
           

                var myFakeWindow = { // define a fake window object
                    document : {
                        write : function(str) {
                          // fake write implementation
                          alert(str);
                        }
                    }
                };
                (function(window) { // wrap pre-existing script with this fakey closure
    this.document.write(‘does alert’);
    window.document.write(‘does alert’);
                    document.write(‘global’);
                }).call(myFakeWindow,myFakeWindow);

    That doesn’t play by the rules of closures. Meaning “window” is set to be “this” and also have it explicitly overridden yet the “document.write” still calls the global window object. huh?

    • http://mutedsolutions.com Derick Bailey

      in this version, you never override anything. you’re creating an object with a “write” method, but never calling it.

      you’ve set the context of your immediate function by using the ‘call’ method, but you’re still using a closure (scope chain) up to the global function to find the “document.write” call from within that.

      if you wanted to use your object instead of the global, you would need to call the version of “write” that is attached to the function’s scope: “this.document.write(…)”.

  • Jason Sebring

    Revised version:

                (function(){
                    var window = { // define a fake window object
                        document : {
                            write : function(str) {
                              // fake write implementation
                              alert(str);
                            }
                        }
                    },
                    document = window.document;
                    (function() { // wrap pre-existing script with this fakey closure
                        document.write(‘global’);
                    })();
                })();

    Looks like you have to explicitly override the global vars, property by property. This would be cumbersome to fake the window object seems. Please advise on this one as I’m interested on how to do that. John Resig? Douglas Crockford?

    • http://mutedsolutions.com Derick Bailey

      yeah, in this version you’re replacing the “write” function on the global “document” object. 

      another way to do this is like I said in the comment for your other version… use the “call” method to set the context of your function and then call “this.document.write” in that…

      var w = {
        document: {
          write: function(){
            // …
          }
        }
      }

      function myFunc(){
        this.document.write(“foo”);
      }

      myFunc.call(w);

      or just pass in an argument to the function:

      function func2(w2){
      w2.document.write(“bar”);
      }

      func2(w);