Book Image

Learning jQuery 1.3

By : Jonathan Chaffer, Karl Swedberg
Book Image

Learning jQuery 1.3

By: Jonathan Chaffer, Karl Swedberg

Overview of this book

<p>To build interesting, interactive sites, developers are turning to JavaScript libraries such as jQuery to automate common tasks and simplify complicated ones. Because many web developers have more experience with HTML and CSS than with JavaScript, the library's design lends itself to a quick start for designers with little programming experience. Experienced programmers will also be aided by its conceptual consistency. <br /><br />Revised and updated for version 1.3 of jQuery, this book teaches you the basics of jQuery for adding interactions and animations to your pages. Even if previous attempts at writing JavaScript have left you baffled, this book will guide you past the pitfalls associated with AJAX, events, effects, and advanced JavaScript language features.<br /><br />In this book, the authors share their knowledge, experience, and enthusiasm about jQuery to help you get the most from the library and to make your web applications shine. The book introduces jQuery and shows how you can write a functioning jQuery program in just three lines of code. It then guides you through CSS selectors and shows how to enhance the basic event handling mechanisms to give them a more elegant syntax. You will then learn to add impact to your actions through a set of simple visual effects and also to create, copy, reassemble, and embellish content using jQuery's DOM modification methods. You will also learn to send and retrieve information with AJAX methods. The book will then step you through many detailed, real-world examples and even equip you to extend the jQuery library itself with your own plug-ins.</p>
Table of Contents (22 chapters)
Learning jQuery 1.3
Credits
Foreword
About the Authors
About the Reviewers
Preface
Index

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 create closures.

Arguments to $(document).ready()

Nearly all of the code we write using jQuery ends up getting placed inside a function passed 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 part of 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 innerFn() {
    readyVar++;
    $('#example-9').print('readyVar = ' + readyVar);
  }
  innerFn();
  innerFn();
});

This looks like many of our earlier examples, except that in this case, the outer function is the callback passed to $(document).ready(). Since innerFn() is defined inside of it, and refers to readyVar which is in the scope of the callback function, innerFn() and its environment create a closure. We can see this by noting that the value of readyVar persists between calls to the function:

readyVar = 1
readyVar = 2

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. Since those inner functions are stored and called later, they can create closures. A simple click handler can illustrate this:

$(document).ready(function() {
  var counter = 0;
  $('#example-10 a.add').click(function() {
    counter++;
    $('#example-10').print('counter = ' + counter);
    return false;
  });
});

Because the variable counter 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's value. Because a closure is created, the same instance of counter is referenced each time the link is clicked. This means that the messages display a continuously incrementing set of values, not just 1 each time:

counter = 1
counter = 2
counter = 3

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

$(document).ready(function() {
  var counter = 0;
  $('#example-11 a.add').click(function() {
    counter++;
    $('#example-11').print('counter = ' + counter);
    return false;
  });
  $('#example-11 a.subtract').click(function() {
    counter--;
    $('#example-11').print('counter = ' + counter);
    return false;
  });
});

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

counter = 1
counter = 2
counter = 1
counter = 0

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

$(document).ready(function() {
  $('#example-12 a').each(function(index) {
    $(this).click(function() {
      $('#example-12').print('index = ' + index);
      return false;
    });
  });
});

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

$(document).ready(function() {
  $('#example-13 a').each(function(index) {
    function clickHandler() {
      $('#example-13').print('index = ' + index);
      return false;
    }

    $(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() {
    $('#example-14').print('index = ' + index);
    return false;
  }

  $('#example-14 a').each(function(index) {
    $(this).click(clickHandler);
  });
});

This version will trigger a JavaScript error whenever a link 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.