Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Learning  jQuery : Better Interaction Design and Web Development with Simple JavaScript Techniques

You're reading from   Learning jQuery : Better Interaction Design and Web Development with Simple JavaScript Techniques Better Interaction Design and Web Development with Simple JavaScript Techniques

Arrow left icon
Product type Paperback
Published in Jul 2007
Publisher Packt
ISBN-13 9781847192509
Length 380 pages
Edition Edition
Languages
Tools
Arrow right icon
Toc

Table of Contents (18) Chapters Close

Learning jQuery
Credits
About the Authors
About the Reviewers
Preface
1. Getting Started FREE CHAPTER 2. Selectors—How to Get Anything You Want 3. Events—How to Pull the Trigger 4. Effects—How to Add Flair to Your Actions 5. DOM Manipulation—How to Change Your Page on Command 6. AJAX—How to Make Your Site Buzzword-Compliant 7. Table Manipulation 8. Forms with Function 9. Shufflers and Rotators 10. Plug-ins 1. Online Resources 2. Development Tools 3. JavaScript Closures

Closures in jQuery


The methods we have seen throughout the jQuery library often take at least one function as a parameter. For convenience, we often use anonymous functions so that we can define the function behavior right when it is needed. This means that functions are rarely in the top-level namespace; they are usually inner functions, which means they can quite easily become closures.

Arguments to $(document).ready()

Nearly all of the code we write using jQuery ends up getting placed inside a function as an argument to $(document).ready(). We do this to guarantee that the DOM has loaded before the code is run, which is usually a requirement for interesting jQuery code. When a function is created and passed to .ready(), a reference to the function is stored as part of the global jQuery object. This reference is then called at a later time, when the DOM is ready.

We usually place the $(document).ready() construct at the top level of the code structure, so this function is not really a closure. However, since our code is usually written inside this function, everything else is an inner function:

$(document).ready(function() {
  var readyVar = 0;
  function outerFun() {
    function innerFun() {
      readyVar++;
      alert(readyVar);
    }
    return innerFun;
  }
  var readyVar2 = outerFun();
  readyVar2();
});

This looks like our global variable example from before, except now it is wrapped in a $(document).ready() call as so much of our code always is. This means that readyVar is not a global variable, but a local variable to the anonymous function. The variable readyVar2 gets a reference to a closure with readyVar in its environment.

The fact that most jQuery code is inside a function body is useful, because this can protect against some namespace collisions. For example, it is this feature that allows us to use jQuery.noConflict() to free up the $ shortcut for other libraries, while still being able to define the shortcut locally for use within $(document).ready().

Event Handlers

The $(document).ready() construct usually wraps the rest of our code, including the assignment of event handlers. Since handlers are functions, they become inner functions and since those inner functions are stored and called later, they become closures. A simple click handler can illustrate this:

$(document).ready(function() {
  var readyVar = 0;
  $('.trigger').click(function() {
    readyVar++;
    alert(readyVar);
  });
});

Because the variable readyVar is declared inside of the .ready() handler, it is only available to the jQuery code inside this block and not to outside code. It can be referenced by the code in the .click() handler, however, which increments and displays the variable. Because a closure is created, the same instance of readyVar is referenced each time the button is clicked. This means that the alerts display a continuously incrementing set of values, not just 1 each time.

Event handlers can share their closing environments, just like other functions can:

$(document).ready(function() {
  var readyVar = 0;
  $('.add').click(function() {
    readyVar++;
    alert(readyVar);
  });
  $('.subtract').click(function() {
    readyVar--;
    alert(readyVar);
  });
});

Since both of the functions reference the same variable, the incrementing and decrementing operations of the two buttons affect the same value rather than being independent.

These examples have used anonymous functions, as has been our custom in jQuery code. This makes no difference in the construction of closures. For example, we can write an anonymous function to report the index of an item within a jQuery object:

$(document).ready(function() {
  $('li').each(function(index) {
    $(this).click(function() {
      alert(index);
    });
  });
});

Because the innermost function is defined within the .each() callback, this code actually creates as many functions as there are list items. Each of these functions is attached as a click handler to one of the items. The functions have index in their closing environment, since it is a parameter to the .each() callback. This behaves the same way as the same code with the click handler written as a named function:

$(document).ready(function() {
  $('li').each(function(index) {
    function clickHandler() {
      alert(index);
    }

    $(this).click(clickHandler);
  });
});

The version with the anonymous function is just a bit shorter. The position of this named function is still relevant, however:

$(document).ready(function() {
  function clickHandler() {
    alert(index);
  }
  $('li').each(function(index) {
    $(this).click(clickHandler);
  });
});

This version will trigger a JavaScript error whenever a list item is clicked, because index is not found in the closing environment of clickHandler(). It remains a free variable, and so is undefined in this context.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image