4
\$\begingroup\$

Now that I've used it a lot, I think I'm starting to get the hang of jQuery and its capabilities. One thing I'm still unclear about is how global variables are initiated and used, and when the variable is in reference to a jQuery object, both cases especially in and with external JavaScript files.

For example, if we had this test website:

HTML file

<!DOCTYPE html>
<html>
  <head>
    <link rel="stylesheet" type="text/css" href="someCSSreset.css">
    <link rel="stylesheet" type="text/css" href="external.css">
    <style>
      .header {
        color: orange;
        background: blue;
        font-size: 1.5em;
      }
      .content {
        color: purple;
        background: pink;
      }
      h1, h2 {
        position: relative;
        margin: 0 auto;
      }
    </style>

    <script src="jQuery.min.js"></script>
    <script src="example.js"></script>
    <script>
      // Global undefined variable. Is this allowed?
      window.globalUndefined;
      // Global variable referencing a number?
      window.globalNumber = 42;
      // Global undefined jQuery object?
      window.$someElement;
      // Global jQuery object. Do I need window. in front of the right-hand statement?
      window.$allP = $("p");

      $(document).ready(function() {
        // Using global variable in document
        $allP.click(function() {
          $(this).css("color", "red");
        });

        // Using global variable from external file internally. Is this correct?
        $allHeaders.click(function() {
          $(this).css("color", "green");
        });

        // Am I passing these correctly?
        doSomething($allP, $allHeaders);
      });
    </script>
  </head>
  <body>
    <div class="header wrap">
      <div class="header main">
        <h1>EXAMPLE PAGE</h1>
        <p>hi guys lol</p>
      </div>
    </div>
    <div class="content wrap">
      <div class="content main">
        <h2>Paragraph 1</h2>
        <p>Lorem ipsum</p>
      </div>
    </div>
  </body>
</html>

And then, our two relevant external files:

external.css

body {
  background-color: light-blue;
  font-family: sans-serif;
  width: 100%;
}
.wrap {
  width: 50%;
  border: 2px solid black;
}

example.js

// Does an external jQuery file need $(document).ready wrappers around it?
// Global undefined variable. Is this allowed?
window.extGlobalVar;
//Global variable referencing a number?
window.extGlobalNumber = 117;
// Global undefined jQuery object?
window.$extElementVar;
// Global jQuery object. Do I need a window. in front of the right-hand statement?
window.$allHeaders = $("h1");

function doSomething(p, h) {
  $(p).mouseOver(function() {
    // Using the internal global number variable?
    $(this).css("width", globalNumber + "px");
  });

  // Using internal global jQuery 
  $allHeaders.mouseOver(function() {
    // Using the external global number variable?
    $(this).css("width", extGlobalNumber + "px");
  });

  // Can I later set the two undefined jQuery objects in the external file, or do I
  // have to do it internally? Or does either work?
  $someElement = $(".wrap");
  $extElementVar = $(".main");
}

That's a lot of questions randomly strewn throughout some shitty code, so I'll reiterate them here:

  1. In the above examples, am I using the various global variables and global jQuery objects correctly (in both the internal and external cases)?
  2. In the above examples, am I passing the two global variables into that (externally-held) jQuery function correctly (in both the internal and external cases)?
  3. Am I calling that (externally-held) jQuery function correctly?
  4. Is there a way to be able to call an externally-held jQuery function on an object internally? E.g. $("div").doSomething(), but doSomething is defined in an external file. If so, how?
  5. If we're allowed to have undefined global variables, can I later set them in the external file, or do they have to be set internally? Or can I do either?
  6. Can you declare global variables in a function or in the $(document).ready() wrapper if you format it as window.$(etc)?
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

Let me first try to clear up what I expect to be some confusion:

All JavaScript code on a page runs in the same environment. Whether a piece of code is defined in an external file or in the page itself makes little difference, as long as things are loaded in the proper order.

So if you had HTML like

<script>
  /* chunk of code 1 */
  /* chunk of code 2 */
  /* chunk of code 2 */
</script>

It's the same as:

<script> /* chunk of code 1 */ </script>
<script> /* chunk of code 2 */ </script>
<script> /* chunk of code 3 */ </script>

Which, in turn is the same as:

<script src="chunk1.js"></script>
<script src="chunk2.js"></script>
<script src="chunk3.js"></script>

From the browser's point of view, all JS - whether part of the HTML or in a separate file - is just part of one big JS file. So in you case, that file starts with all of jQuery's code, then the code from "example.js" and then the code in the HTML.

So when you say "externally-held" and "internally-held", I say "same difference". Functions, where ever they're defined, have their own internal scope (and access to any "outer" scope) - files do not automatically constitute a scope.

To answer your questions directly:

In the above examples, am I using the various global variables and global jQuery objects correctly (in both the internal and external cases)?

Yes and no. Yes in the sense that you're doing it right, but no in the sense that you may not be doing the right thing :)

Global variables are useful ($ aka jQuery is a global variable), but the fewer you have, the better. JavaScript is the wild west: Browsers and libraries may define different things in the global scope, so it's easy to step on something's toes - or have your own toes stepped on, if some library accidentally overwrites your global variables.

So the usual guideline for JavaScript is to avoid "polluting the global scope". Hence why jQuery "hides" (almost) all its functionality behind the $ variable: It limits jQuery's footprint to a single variable (even so, there were libraries before jQuery that used the global $ for something, so things can still get weird).

So, again, yes, those are global variables, and - since everything is essentially one big file - you're doing that part right. But even so, I wouldn't recommend it.

In the above examples, am I passing the two global variables into that (externally-held) jQuery function correctly (in both the internal and external cases)?

Again: Yes and no. It certainly makes sense to pass them - but it's not necessary to make them global to begin with.

Am I calling that (externally-held) jQuery function correctly?

Sure - again: One great big file.

Is there a way to be able to call an externally-held jQuery function on an object internally? E.g. $("div").doSomething(), but doSomething is defined in an external file. If so, how?

Yes: Plugins. Plugins are how you extend jQuery with custom functionality. It's slightly more involved than just writing a function, but it's not too bad.

Still, consider if it's worth it. The functionality you're adding should be somewhat generic to really make sense. For instance, jQuery UI defines a bunch of plugins to animate elements and such. This works for any element, on any page. The same way jQuery itself makes sense on any page, anywhere.

But if your functionality is more specific (i.e. only works in your specific circumstances) don't bother with plugins. Functions work just fine too. Sure, it may not be quite as neat as writing $("div").doSomething(), but it's a lot more flexible. You can define tons of plugins, but.. eh', not worth it.

In your case, your doSomething function relies on global variables, and its functionality is very specific (in other words, it's tightly coupled to your circumstances), so making it a plugin would be complicating matters.

Still, as an example, here's a plugin that makes the background of an element red (that is, a fairly generic - if useless - piece of functionality that doesn't rely on a specific context):

jQuery.fn.paintItRed = function () {
  this.each(function () {
    $(this).css('background', 'red');
  });
  return this;
};

You can then use $("div").paintItRed(), and it'll make all the DIVs red! Yay?

If we're allowed to have undefined global variables, can I later set them in the external file, or do they have to be set internally? Or can I do either?

Well, undefined means just that: Not defined. At all. So if you do nothing at all, the variable will be undefined. it also means that doing this:

window.anUndefinedVariable;

doesn't do anything really. You're not really declaring anything (at best, JavaScript will attempt to read the variable, which isn't defined).

And again, we're back to why global scope pollution is a problem: Any piece of code can define or overwrite a global variable. So for instance, jQuery defines $ as a global variable, but your code can easily re-define it as null - and then you can't use $ for anything.

Can you declare global variables in a function or in the $(document).ready() wrapper if you format it as window.$(etc)?

Sure. In browsers, window is the global object. And, as mentioned, any piece of code can run code like window.someGlobal = 23;.

That's because window is just another object, and any object your code can access, it can mess with.


This is getting pretty long-winded (sorry), but you've got a few more question in your code, and I'll quickly want to answer one of those:

// Does an external jQuery file need $(document).ready wrappers around it?

Yes, if your code need to access element in the page. If you load your file at the top of the HTML, it starts running before the page itself has actually been parsed. Again: Just the same as if that file's content was actually embedded in the page itself.

So whenever you want to make sure that the page has actually been fully downloaded and parsed, you have to use $(document).ready(function () {...}) - or its shortcut: $(function () {...});

It's no different from a click event. You want some code to run when something's clicked - not before! So you use $("#something").click(function () {...}), and you know that that function's code will only run when the "something"-element is clicked. Similarly, $(document).ready is just another event listener, which waits for the ready event to fire before running the function.

Phew - sorry for the verbiage.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.