Chapter 3

The jQuery Core

WHAT’S IN THIS CHAPTER?

  • jQuery Utility Functions
  • Unobtrusive JavaScript the Structure of the jQuery Framework
  • Understanding the DOM and Events

With a good grasp of JavaScript, you’re now ready to tackle the jQuery core. As you know, it has a small footprint, and rather than a mishmash of functionality it has a coherent base. It provides the capacity to easily select elements, separating the behavior of the document from its structure, as well as the ability to manipulate the DOM on the fly.

In this chapter, you learn about basics of using the jQuery core, about wrapper objects, and briefly take a look under the hood. You’ll find it useful to have some IDE with the ability to collapse blocks of code when perusing through the jQuery source. You’ll also revisit DOM elements and how jQuery handles events.

UNDERSTANDING THE STRUCTURE OF A JQUERY SCRIPT

Some mainstream languages (which shall go unnamed) contain a monolithic “standard library,” which really isn’t so standard. Rather than using a standard library with a common denominator set of tools, several additional modules are added. This results in unnecessarily large downloads, wasted resources, and functionality that you may never use. On the other hand, the creators of jQuery very thoughtfully kept out these kinds of “add on” modules, and kept the jQuery core small and compact. It is, however, extensible through the plugin system, which is covered in Chapter 12.

The jQuery core function, sometimes also referred to as a factory object, is referenced as either jQuery() or, more commonly, by its alias $(). If you recall from the JavaScript primer, this is a completely valid name for a variable. In this case, the variable has the type of “function.” This function accepts either a selector string, a string of raw HTML, a DOM element, an existing jQuery object, or no argument at all. The function returns a jQuery object which also has several methods attached to it, for example, $.ajax() or $.each(). More on these later.

Typically, your scripts will follow the pattern shown in the following code snippet. Remember to include the jQuery JavaScript file before any other dependent code.

<!DOCTYPE html>
<html>
  <head>
    <script src=”jquery.js”></script>
    <script >
... jquery code here
    </script>
  </head>
  <body>
<!--
tags here, no embedded javascript here
-->
  </body>
</html>

The doctype declaration, as always, is placed at the beginning of the HTML file, even before the html tag, to indicate the document definition type (DTD). In this book, you will always use the HTML 5 doctype, which is very simply:

<!DOCTYPE html>

Most of the time when you use jQuery, you’ll follow the pattern of selecting a DOM element, or set of DOM elements, performing some operation or manipulation on the selected element(s). Select and manipulate, rinse and repeat. The basic call to jQuery is

$(selector);

where selector is a string-enclosed expression for matching DOM elements. The selector format is the same used with CSS, so you can carry over your existing knowledge of CSS to jQuery. For example, # matches elements by their id attribute and . matches by CSS classes. For example, to get a div with the ID feed use the following:

$(“div#feed”);

The next chapter covers selectors in-depth.

When using the jQuery object to either select elements or create new elements, it returns what’s known as a wrapper object. It’s called a wrapper object because you “wrap” jQuery functionality around a collection of DOM elements. A wrapper object is array-like, meaning you can index it with square brackets or check the number of elements using its .length property. I’ll use the .length property often to verify that a selector matched a set of elements. It’s easy to check out the .length property of a jQuery wrapper using the Firebug console.

When you call a jQuery method, such as .addClass(), it applies the method to all of the selected elements. There’s no need to iterate over the collection with a loop.

We’ve mentioned that the jQuery object contains several methods. Table 3-1 shows a sampling of just some of them.

TABLE 3-1: jQuery Methods

METHOD CATEGORY DESCRIPTION
.ready() Events Specifies a function to run when the DOM is fully loaded.
.click() Events Sets click event handlers on the set of matched elements.
.ajax() Ajax jQuery’s Ajax utility.
.addClass() CSS Adds a CSS class to the set of matched elements.
.removeClass() CSS Removes a CSS class from the set of matched elements.
.attr() Attributes Gets or sets the value of the specified attribute.
.html() Attributes, DOM Insertion Gets or sets the HTML content of the first matched element.
.type() Utility Determines the internal JavaScript [[Class]] of an object.

jQuery is eco-friendly; it doesn’t pollute the namespace with globals except for jQuery and $. Although the $ alias might be used in other libraries, it’s highly unlikely that any other library uses jQuery as a variable.

Utility Functions

If you recall, functions are also objects. Hence, a function may have properties and its own methods. The jQuery object has several useful methods conveniently called utility methods. Methods exist for enhancing operations for arrays, objects, functions, and even data manipulation.

Objects

The plain-old JavaScript way of checking the type of an object is using the typeof()operator , which is sometimes inconsistent. In some instances typeof() returns an incorrect or unexpected value. Take for example typeof(null) — it returns object instead of null. Luckily, jQuery has a custom .type() method for these situations:

$.type(null); // returns null
$.type([]); // returns array

The .isEmptyObject() method is used to test whether an object contains any properties, including inherited properties, independent of object type:

$.isEmptyObject(“”); // returns true
$.isEmptyObject({}); // returns true
 
var mailman = {};
mailman.letters = 100;
$.isEmptyObject(mailman); // returns false

There’s a similar .isPlainObject() method. It also tests whether an object contains any properties, but must be of an Object instance. So an empty string will return false in this case:

$.isPlainObject(“”); // false
$.isPlainObject({}); // true
$.isPlainObject(new Object); // true

You mention, “OK, that’s great, but what else can I do with objects?” Glad you asked. You can also merge two or more objects with the .extend() method. More specifically, .extend() combines the properties of one or more objects into a target object. In the next example, obj1 receives the properties of obj2 and obj3:

var obj1 = {“1”:”property 1”}; 
var obj2 = {“2”:”property 2”};
var obj3 = {“3”:”property 3”};
$.extend(obj1, obj2, obj3);
console.log(obj1[“3”]); // displays property 3

An interesting note about .extend() is that you can use it to clone JavaScript objects (this is different from the $.clone() method):

var clonedObject = $.extend({}, anObject);

$.extend() accepts an additional first argument for doing a deep merge of objects, in other words, a recursive copy. You can also use this to do a deep clone of objects as well:

var clonedObject = $.extend(true, {}, anObject);

Functions

jQuery has two utility methods for functions: .isFunction() and .noop(). As its name implies, .isFunction() tests whether an object is also a function. Make sure not to use parentheses in the function name. In the next example, .isFunction() is passed to itself. Because it is itself a function, it must return true.

$.isFunction({}); // false
$.isFunction($.isFunction); // true
$.isFunction($.isFunction()); // false, because of parenthesis

The .noop() method is a stub function; it doesn’t perform any operation. But, it’s still useful for moments when you’d like to pass an empty function as an argument, e.g., to install a new event that does nothing by default.

Array Operations

Similar to .isObject() and .isFunction(), you also have an .isArray() at your disposal. Besides checking whether an object is an array, you can turn an array-like object to a true array using .makeArray(). By converting an array-like object to an array, you lose its methods and properties. The following illustrates a simple usage of makeArray which converts a cloned version of jQuery into a standard Array.

// clone jQuery object
var clonedjq = $.extend(true, {}, $); 
//returns “object”
$.type(clonedjq);
 
// convert to JS array
var jqArray = $.makeArray(clonedjq); 
 
// returns “array”
$.type(jqArray);

jQuery also provides an additional convenience method for combining arrays called .merge(), which takes the elements from a second array and appends them to the elements of a first array, preserving the order of the elements of the two arrays:

var spooks = [“wraiths”, “vampires”, “lichs”];
var nums = [1,2,3];
var mergedArrays = $.merge(spooks, nums);
alert(mergedArrays); // displays: wraiths, vampires, lichs, 1, 2, 3

The next two methods are useful for working with the elements of an array. .inArray() checks for the existence of a value (in the array no less) and returns the index of the value if found. If the value isn’t in the array, -1 is returned. The $.unique() removes duplicate elements from an array of DOM elements. This following snippet demonstrates both methods:

image
<!DOCTYPE html>
<html>
  <head>
  </head>
  <body>
    <p></p>
    <p></p>
    <p></p>
    <p class=”duplicate”></p>
    <p class=”duplicate”></p>
    <p class=”duplicate”></p>
    <p></p>  
    <script 
        src=”http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js”>
    </script>
    <script>     
      $(document).ready(function(){
          // select all paragraph elements
          var paragraphs = $( “p” ); 
          
          //returns 7 
          console.log( paragraphs.length );
       
          //turn it into an array
 
          paragraphs = $.makeArray( paragraphs );
          
          //get elements of class duplicate and immediately convert them to an array
          var dupes = $.makeArray($( “.duplicate” ))
 
          //concat them into our paragraphs array 
          paragraphs = paragraphs.concat( dupes );
          
          //returns 10
          console.log( paragraphs.length );
          
          //get rid of the dupes
          paragraphs = $.unique( paragraphs );
          
          //returns 7
          console.log( paragraphs.length );
          
           var index = $.inArray(“6”, paragraphs);
          console.log(index); // returns -1
      });
    </script>
 
  </body>
</html>

Code snippet is from in-array-and-unique.tx

Using a jQuery tag selector, you get all of the paragraph elements, then using .makeArray() you convert to a plain-old JavaScript array. You then use a jQuery class selector to get all elements of class “duplicate” and add them into our original paragraphs array. With that action, paragraphs now contain duplicate elements. Its total length is 10. Then using .unique() you get the set of paragraph elements without the duplicates. Its total length is now 7. Finally, you check for “6” in the list of paragraphs, which of course returns -1.

You can iterate through an array using an old-fashioned for loop, but as you’ve probably predicted, jQuery has an alternate method called .each(). This will work with objects, array-like objects, and arrays. $.each() is zero-based and accepts two arguments: the collection to iterate over and a callback function. The callback function accepts the arguments: the index currently operated on and the element value. The following code illustrates using $.each() to iterate over the members of a simple array:

image
<!DOCTYPE html>
<html>
  <head>
    <script type=”text/javascript” src=”jquery.js”></script>
    <script type=”text/javascript”>     
      $.ready(function(){
          var numArray = [1,2,3,4];
          $.each(numArray, function(index, value){
              value = value ∗ 2;
              console.log(“index is:”+index+” new value is:”+value);
          });          
      });
    </script>
  </head>
  <body>  
  </body>
</html>

Code snippet is from each.txt

The last jQuery utility method for working with arrays you’ll check out is .map(), which has a similar syntax to .each(), accepting an array or array-like object as its first argument and a callback function. The callback function — according to the jQuery docs, is a “. . . function to process each item against” — accepts one of the array elements and its current index.

image
<!DOCTYPE html>
<html>
  <head>
    <script type=”text/javascript” src=”jquery.js”></script>
    <script type=”text/javascript”>     
      $.ready(function(){
          var numArray = [42,1024,486,109821];
          console.log(numArray);
           var newArray = $.map(numArray, function(value, index){
            return Math.sqrt(value).toFixed(4);
           });
          //logs [“6.4807”, “32.0000”, “22.0454”, “331.3925”]
          console.log(newArray);
      });
    </script>
  </head>
  <body>  
  </body>
</html>

Code snippet is from map.txt

Data Structures

A queue is a “First In, First Out” data structure, meaning elements are added to the back and removed from the front. In jQuery, you can use $.queue() to maintain a list of functions. The default function queue is fx, the standard effects queue. In the fx context the power of queues is very clear. The following code sample illustrates a simplified animation queue. Our animation div slides up and then, when it’s finished, the next animation in the queue, the fadeIn, runs.

$('#animation').slideUp().fadeIn();

The $.queue supports the operations push and pop. To remove all functions from a queue, use .clearQueue(). Using the corresponding method .dequeue() you can remove an item from a queue and execute it. The following code sample shows a simplified example of a manual usage queue and dequeue. A second animation is added to the queue, and then is pulled off the stack and executed with dequeue.

image
<!DOCTYPE html>
<html>
<head>
  <script type='text/javascript' src='http://code.jquery.com/jquery-1.7.1.js'></script>
  <style type='text/css'>
    #animation {
        width:200px;
        height:200px;
        background:#ccc;
    }
    </style>
 
    <script type='text/javascript'> 
      $.ready (function(){
      $(“#animation”).show(“slow”);
      $(“#animation”).queue(function () {
          $(this).animate({width:'+=400'},1000);
          $(this).dequeue();
       });
        }); 
    </script>
    </head>
    <body>
    <div id =”animation” style=”display:none”></div>
  </body>
</html>

Code snippet is from queue-and-dequeue.txt

Strings

There is just one utility method for working with strings: .trim(). JavaScript already contains a powerful mechanism for working with strings via its regular expressions, but its string objects don’t contain a built-in .trim() method. As the following code example illustrates, trimming removes the trailing and leading whitespaces from a string.

     var phrase1 = “      1. Either this wallpaper goes          ”;
    var phrase2 = “ or I go.                                    ”;
   
    // Last words of Oscar Wilde
    var quote = $.trim(phrase1) + “ “ + $.trim(phrase2);
    console.log(quote);
    //logs 1. Either this wallpaper goes or I go.

Data

Ajax is a major part of the modern Web. The ability to wire data from client to server and back again, without a full page refresh, has resulted in a serious usability boon for modern web applications. Two of the most common data exchange formats are XML and JSON (JavaScript Object Notation). jQuery has the ability to parse both formats locally and over a URL with the .parseXML() and .parseJSON() methods. You learn about those later when you explore Ajax.

Arbitrary data can be attached to HTML element storage/retrieval. The utility method .data() is used for this purpose. .data() will be covered in detail in Chapter 6.

Other Useful Utility Methods

These last few utility methods don’t fit into any of the other categories: .contains(), .isWindow(), .isXMLDoc(), .now(), .support(), and .globalEval(). This section tackles each one.

Checking for Subnodes

The method .contains() checks to see if a DOM node is a child, or subnode, of another node. It expects two arguments — the possible container and the contained node:

$.contains($(“head”)[0], $(“title”)[0]); //

The jQuery wrapper is array-like, so to get the reference to the actual element, you’ll need to use the square brackets to retrieve the element references. The title tag is always a child of the head tag, and hence returns true.

Checking for Windows

Consider the situation were you have an iframe. In one of your operations you may want to distinguish between that iframe and the browser window. To do this use the .isWindow() method:

image
<!DOCTYPE html>
<html>
  <head>
    <script type=”text/javascript” src=”jquery.js”></script>
    <script type=”text/javascript”>     
      $.ready(function(){
          var inlineFrame = $(“#frame”)[0];          
          $.isWindow(inlineFrame); // returns false
          $.isWindow(window);      // returns true  
      });
    </script>
  </head>
  <body>
    <iframe id=”frame” src=”externalPage.html”></iframe>  
  </body>
</html>

Code snippet is from isWindow.txt

Determining the Current Time

For checking the current time, use the $.now() shortcut, as its name implies. It’s a shortcut for (new Date).getTime(), and obviously it’s much easier to just write $.now().

Detecting Browser Features

You’ve probably heard that it’s better to detect browser features rather than detect browsers. Using the .support() method you can detect what features a browser supports. This function deprecates $.browser from earlier versions of jQuery. A good example of its use: if ($.support.ajax) { } to check if a browser supports Ajax requests (aka XMLHttpRequest object creation).

Evaluation in the Global Context

The last utility method we’ll look at is .globalEval(). You may recall the eval() expression, used to execute arbitrary JavaScript code:

// create a variable x, and initialize it to 0 after all DOM elements are loaded
$(function(){
    eval(“var x = 0;”);
});

The execution context of eval is not global, but rather local. You may want the execution context for statements you’re evaluating to exist globally, for example when loading external JavaScript files. This is where .globalEval() comes into play:

// now in global context
$(function(){
    $.globalEval(“var x = 0;”);
});

Table 3-2 summarizes all of the utility methods discussed.

TABLE 3-2: Summary of Utility Methods

METHOD CATEGORY DESCRIPTION
$.type() Utilities Determine the internal JavaScript [[Class]] of an object.
$.isEmptyObject() Utilities Check to see if an object is empty (contains no properties).
$.isPlainObject() Utilities Check to see if an object is a plain object (created using “{}” or “new Object”).
$.extend() Utilities Merge the contents of two or more objects together into the first object.
$.isFunction() Utilities Determine if the argument passed is a JavaScript function object.
$.noop() Utilities An empty function.
$.inArray() Utilities Search for a specified value within an array and return its index (or -1 if not found).
$.isArray() Utilities Determine whether the argument is an array.
$.makeArray() Utilities Convert an array-like object into a true JavaScript array.
$.merge() Utilities Merge the contents of two arrays together into the first array.
$.map() Utilities Pass each element in the current matched set through a function, producing a new jQuery object containing the return values.
$.each() Utilities A generic iterator function, which can be used to seamlessly iterate over both objects and arrays. Arrays and array-like objects with a length property (such as a function’s arguments object) are iterated by numeric index, from 0 to length -1. Other objects are iterated via their named properties.
$.unique() Utilities Sort an array of DOM elements, in place, with the duplicates removed. Note that this only works on arrays of DOM elements, not strings or numbers.
$.queue() Data, Utilities Show the queue of functions to be executed on the matched element.
$.clearQueue() Custom, Data, Utilities Remove from the queue all items that have not yet been run.
$.dequeue() Data, Utilities Execute the next function on the queue for the matched element.
$.trim() Utilities Remove the whitespace from the beginning and end of a string.
$.grep() Utilities Find the elements of an array which satisfy a filter function. The original array is not affected.
$.contains() Utilities Check to see if a DOM element is within another DOM element.
$.data() Data, Utilities Store arbitrary data associated with the specified element. Returns the value that was set.
$.parseXML() Utilities Parse a string into an XML document.
$.parseJSON() Utilities Take a well-formed JSON string and return the resulting JavaScript object.
$.isWindow() Utilities Determine whether the argument is a window.
$.isXMLDoc() Utilities Check to see if a DOM node is within an XML document (or is an XML document).
$.now() Utilities Return a number representing the current time.
$.support() Properties of the Global jQuery Object , Utilities A collection of properties that represent the presence of different browser features or bugs.
$.globalEval() Utilities Execute some JavaScript code globally.

USING JAVASCRIPT UNOBTRUSIVELY

In the dark days of JavaScript, code like the following was common:

image
<!DOCTYPE html>
<html>
  <head>
    <script type=”text/javascript”>
      function showStuff(){
        var content = document.getElementById(“content”);
        content.style.display = “block”;o com
      }
 
      function changeBGColor(elem){
        elem.style.backgroundColor = “green”;
      }
    </script>
  </head>
  <body>
    <ul id=”content” onLoad=”javascript:showStuff();” style=”display:none;”>
      <li onClick=”javascript: changeBGColor(this);”>Item 1</li>
      <li onClick=”javascript: changeBGColor(this);”>Item 2</li>
      <li onClick=”javascript: changeBGColor(this);”>Item 3</li>
      <li onClick=”javascript: changeBGColor(this);”>Item 4</li>
    </ul>
  </body>
</html>

Code snippet is from dark-days.txt

You might have cringed at the sight of an embedded CSS style in one of the tags. It’s a common tenet of standards-based web development that presentation information, in the form of CSS styles, should be separated from the content and structure of the page, represented by the HTML. To do this with the preceding example, the styles should be placed in an external CSS file. The improved example should look more like this:

image
<!DOCTYPE html>
<html>
  <head>
    <style type=”text/css” src=”myCss.css”></style>
    <script type=”text/javascript”>
      function showStuff(){
        var content = document.getElementById(“content”);
        content.style.display = “block”;
      }
 
      function changeBGColor(elem){
        elem.style.backgroundColor = “green”;
      }
    </script>
  </head>
  <body>
    <ul id=”content” onLoad=”javascript:showStuff();” class=”contentClass”>
      <li onClick=”javascript: changeBGColor(this);”>Item 1</li>
      <li onClick=”javascript: changeBGColor(this);”>Item 2</li>
      <li onClick=”javascript: changeBGColor(this);”>Item 3</li>
      <li onClick=”javascript: changeBGColor(this);”>Item 4</li>
    </ul>
  </body>
</html>

Code snippet is from separation-of-content-and-style.txt

What’s true for the markup (HTML) and style (CSS) is also true for the behavior (JavaScript). Code representing the behavior of the page should also be removed from the page. Inline event handlers, and inline JavaScript should be avoided wherever possible. This is called unobtrusive JavaScript. The following code sample shows the preceding example rewritten to fully separate style, content and behavior.

image
<!DOCTYPE html>
<html>
  <head>
    <style type=”text/css” src=”myCss.css”></style>
    <script>
 
     (function(document){
          document.onload = function(){
              content.style.display = “block”;
          }
 
          var listItems = document.getElementsByTagName(“li”);          
          for(i = 0; i < listItems.length; i++){
              listItems[i].onclick = function{
                  listItems[i].style.backgroundColor = “green”;    
              }                           
          }          
      })(document);
 
    </script>
  </head>
  <body>
    <ul id=”content” class=”contentClass”>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
      <li>Item 4</li>
    </ul>
  </body>
</html>

Code snippet is from separation.txt

That’s much better on the eyes — the HTML is semantic and the JavaScript unobtrusive. The markup is exactly that, markup not behavior. But, the JavaScript is fairly verbose. This is where jQuery makes life much easier:

image
<!DOCTYPE html>
<html>
  <head>
    <style type=”text/css” src=”myCss.css”></style>
    <script src=”jquery.js”></script>
    <script>
      $(document).ready(function(){
          $(“#content”).show();
          $(“li”).click(function(this){
              this.css(“backgroundColor”,”green”);
          });
      });
    </script>
  </head>
  <body>
    <ul id=”content” class=”contentClass”>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
      <li>Item 4</li>
    </ul>
  </body>
</html>

Code snippet is from unobtrusive.jquery.txt

Immediately, you’ll notice that the JavaScript code shrank from 11 lines to 7; not bad. The document DOM element is passed into the jQuery function. jQuery wraps it, then applies to the returned wrapper a .ready() method.

The .ready() method registers a handler, which executes code after all of the DOM elements have been loaded, but not necessarily all assets (like images or Flash files) and accepts a function as an argument. For example, the following code sample shows a functionToExecute(), which is passed to .ready() While this pattern works technically, it has the unwanted side effect of adding to the namespace a function that is executed only once.

function functionToExecute(){
   // do stuff here
}
$(document).ready(functionToExecute);

This is a perfect place to use an anonymous function instead.

$(document).ready(function(){
  // do stuff here
});

In the previous example, after the DOM is loaded, the content unordered list is made visible, and then all of the list items in the document are given an onClick event handler, which changes the background color to green using the .css() method.

The .ready() method (or event) used in this example can also take the form

$(function(){
  // on ready code goes here
});

which is functionally equivalent, but more abbreviated. For the remainder of this book, we’ll use the latter form.

Finally, the JavaScript code is moved to a separate file called unobtrusive.js:

image
<!DOCTYPE html>
<html>
  <head>
    <style type=”text/css” src=”myCss.css”></style>
    <script type=”text/javascript” src=”jquery.js”></script>
    <script type=”text/javascript” src=”unobtrusive.js”></script>
  </head>
  <body>
    <ul id=”content” class=”contentClass”>
      <li>Item 1</li>
      <li>Item 2</li>
      <li>Item 3</li>
      <li>Item 4</li>
    </ul>
  </body>
</html>

Code snippet is from full-separation.txt

With this approach, the artist can do his/her job without affecting the markup of the page, and the programmer can do his/her job without conflicting with the artist’s changes.

This is a good moment to explain chaining, an often used feature of jQuery. Consider the following code:

image
<!DOCTYPE html>
<html>
  <head>
    <style type=”text/css”>
      .class1 {
         color: “white”,
         background-color: “black”,
         width:200px,
         height:100px 
      }
      .class2 {
         color: “yellow”,
         background-color: “red”,
         width:100px;
         height:200px; 
      }
 
    </style>
    <script type=”text/javascript” src=”jquery.js”></script>
    <script type=”text/javascript”>
      $(function(){
          $(“#myDiv”).addClass(“class1”);
          $(“p#blah”).removeClass(“class1”);
          $(“p#blah”).addClass(“class1”);
      });
    </script>
  </head>
  <body>
    <div id=”myDiv”>
      <p id=”lorem”>Lorem Ipsum</p>
      <p id=”blah”>blah blah blah</p>
    </div>
  </body>
</html>

Code snippet is from no-chaining.txt

Here you have three calls to the jQuery function; each selects an element from the DOM and performs some operation like adding or removing a CSS class to an element. There’s not actually anything wrong with this, but there is a more efficient method. A call to the jQuery function with a selector argument returns an instance of a jQuery object with a collection of selected DOM elements wrapped.

Several jQuery methods also return wrapped objects. For example:

$('body').find('div'),

Because .find() returns another wrapper object, you can do another successive method invocation like so:

$('body').find('div').addClass('cssClass'),

This is called chaining and it’s not unusual to see long jQuery method chains. Besides readability, this also has a performance advantage over instantiating a new jQuery object, searching through the DOM, and then applying a method. Here’s the rewritten example using chaining instead of separate instances:

image
<!DOCTYPE html>
<html>
  <head>
    <style type=”text/css”>
      .class1 {
         color: “white”,
         background-color: “black”,
         width:200px,
         height:100px 
      }
      .class2 {
         color: “yellow”,
         background-color: “red”,
         width:100px,
         height:200px 
      }
 
    </style>
    <script type=”text/javascript” src=”jquery.js”></script>
    <script type=”text/javascript”>
      $(function(){
          $(“#myDiv”)
           .addClass(“class1”)
           .find(“p#blah”)
           .removeClass(“class1”)
           .addClass(“class1”);
      });
    </script>
  </head>
  <body>
    <div id=”myDiv”>
      <p id=”lorem”>Lorem Ipsum</p>
      <p id=”blah”>blah blah blah</p>
    </div>
  </body>
</html>

Code snippet is from chaining.txt

Using Cody Lindley’s terminology, any jQuery method that returns another wrapper object is denoted as a “constructive” method because it can continue a chain, whereas any method that doesn’t return a wrapper (like .text() or .html()) is denoted a “destructive” method.

Writing Less Verbose JavaScript with jQuery

JavaScript, although a very powerful language in its own right, is sometimes verbose. JavaScript frameworks like jQuery offer numerous shortcuts for reducing the amount of code needed to accomplish common web development tasks. You’ve already seen a few:

JAVASCRIPT WAY

window.onload = function() {
    var elements = document.getElementsByTagName(“div”);
    for(var = 0; i < elements.length; i++){
        elements[i].style.color = green;
    }
});

JQUERY WAY

$(function(){
    $(“div”).each(function(index, value){
        $( this ).css( "color" , "green" )
    });
});

The code feels more concise and abbreviated, and although the difference between the number of lines of code isn’t big overall, you wrote much less. It quickly becomes a habit to use the $(function(){...}); instead of window.onLoad().

Of course, there are other, deeper benefits to using a library like jQuery. Shorter code is nice, but adding powerful features in a cross-browser way is even better. In this specific example, jQuery grants you the ability to, in a cross-browser way, set multiple callbacks for the onLoad event. Without a cross-browser solution only one callback could be set for events which meant that you could accidentally overwrite methods if you weren’t careful.

As an aside, this problem was originally solved by the community centering on a series of blog posts by the influential JavaScript developer Dean Edwards: http://dean.edwards.name/weblog/2005/09/busted/ and http://dean.edwards.name/weblog/2006/06/again/. One name that appears as an important contributor to the completed solution was none other than the creator of jQuery, John Resig.

THE JQUERY FRAMEWORK STRUCTURE

Because jQuery is a well-written modular framework, it’s easy to treat it as a black box. But, it’s instructive to look at the underlying code, and see how the nuts and bolts go together. If you’re interested, as of jQuery 1.3, the selector engine is now based on a separate project by John Resig, called sizzle, and offers several performance enhancements over the previous method for selecting elements. See http://sizzlejs.com for more.

If you recall from Chapter 2, a self-invoking anonymous function looks like this:

(function(arguments){
  // do something
})();

jQuery is also a self-executing anonymous function, which accepts two arguments — the window object and undefined:

 (function( window, undefined)  
  {...} // definition of core
) (window);

The window object is passed in as a small performance boost. For any call to the global window object inside the jQuery function definition, instead of looking up the definition of the window in the global context, it looks inside the local context avoiding one step in the lookup. It’s small, but does represent an improvement.

At first, it might seem a little baffling to pass in undefined, but there is a good reason. The undefined built-in type is assignable. So, conceivably, someone on your development team could do something like undefined = true; and then your comparisons won’t work as expected. (Paul Irish has a special term for team members like this; see his video on “10 Things I Learned from the jQuery Source” at http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/.)

Looking further down in the code, you can see how the utility methods are added to the jQuery function:

...
jQuery.extend({
      noConflict: function( deep ){
       ...
      isFunction: function( obj ){
      ...
      isArray: Array.isArray || function( obj ){
...

The jQuery function is .extend()-ed with an object literal, with key-value pairs of method names to method definitions, as you can see from the previous snippet taken from jQuery source. Looking through the method definitions you can see exactly how the comparisons are done, and what each method expects.

Our favorite lesson from looking at the source is how the $.ready() works. There isn’t an .onReady() event in the DOM. Again, looking at the source code is instructive:

// The DOM ready check for Internet Explorer
function doScrollCheck() {
      if ( jQuery.isReady ) {
            return;
}
 
      try {
            // If IE is used, use the trick by Diego Perini
            // http://javascript.nwbox.com/IEContentLoaded/
            document.documentElement.doScroll(“left”);
      } catch(e) {
            setTimeout( doScrollCheck, 1 );
            return;
      }
 
      // and execute any waiting functions
      jQuery.ready();
}
 
// Expose jQuery to the global object
return jQuery;
...

.ready() executes when all of the DOM elements are loaded, but not necessarily all parts of the page, such as images or Flash files. At this point, it’s nice to have the capacity to manipulate the DOM at once. The JavaScript method .doScroll() throws an exception when you try to run it and the DOM isn’t loaded. The call to doScroll() is wrapped around a try/catch statement. When an exception occurs (while the DOM elements are loading), the doScrollCheck() method calls itself recursively, until the DOM is fully loaded. At that point, doScroll stops causing an exception, and jQuery then executes the code bound to .ready().

This section is very small, and doesn’t really do justice to all of the powerful coding techniques used in jQuery. But, we highly recommend that you look through it, and apply the ideas to your own projects.

UNDERSTANDING THE DOM AND EVENTS

Both HTML and XML are hierarchical tree structures of tags (or elements). The window contains a document; documents contain an HTML element, which in turn contains a child header and body element, and so forth. The best definition of the DOM is the one specified by the W3C:

“The Document Object Model is a platform- and language-neutral interface that will allow programs and scripts to dynamically access and update the content, structure and style of documents. The document can be further processed and the results of that processing can be incorporated back into the presented page.”

Most of the cross-browser concerns pertaining to variations in the DOM are silently taken care of for you in jQuery. You don’t need to worry (much) about the differences in the DOM redundant between the Gecko-friendly browsers, IE, Safari, and Opera.

USING JQUERY WITH OTHER JAVASCRIPT LIBRARIES

From time to time you may want to include in your program other JavaScript frameworks or libraries with your code. If those frameworks use the dollar sign as a variable, this will cause conflicts. But, because jQuery plays nice with others, it has a method for avoiding these conflicts. To do so, use the $.noConflict(); method after loading the libraries that may conflict. This has the effect of reverting the dollar sign to its previous value. After invoking .noConflict(), use jQuery instead of $ to refer to the jQuery core. The following code demonstrates an example:

<html>
 <head>
   <script src=”conflictingFramework.js”></script>
   <script src=”jquery.js”></script>
   <script>
     jQuery.noConflict();
     
     jQuery(“<p>I am a paragraph</p>”).appendTo(body);       
     
     // $ references conflictingFramework.js, not jQuery
     $.blahMethodFromOtherLibrary();
   </script>
 </head>
 <body>
 </body>
 </html>

Opening up the hood, you can see the actual definition of $.noConflict():

...
noConflict: function( deep ) {
    window.$ = _$;
 
    if ( deep ) {
        window.jQuery = _jQuery;
    }
 
    return jQuery;
},
...

As you can see, it’s very short. jQuery maintains an internal reference to the value of $ — after $.noConflict is called, the value of $ is restored to its previous value, which is the value of the conflicting library.

SUMMARY

In review, you’re now familiar with the structure and syntax of jQuery-based JavaScript programs, taking view of how jQuery makes use of the pattern of unobtrusive JavaScript separating behavior from markup. Without fear or reserve, you’ve also taken a very basic tour of the jQuery core. Choosing not to treat jQuery as a black box gives you an advantage over many other web developers. Studying the core also teaches several JavaScript techniques that you can apply in your own projects.

Now that you’ve had some exposure to the basics, you can delve into one of the most powerful features of jQuery — its very complete selector mechanism — in the following chapter.

NOTES

http://jqfundamentals.com/book/index.html#example-3.13

http://paulirish.com/2010/10-things-i-learned-from-the-jquery-source/

http://ejohn.org/blog/ultra-chaining-with-jquery/

http://perfectionkills.com/instanceof-considered-harmful-or-how-to-write-a-robust-isarray/

http://stackoverflow.com/questions/5773723/difference-between-jquery-isplainobject-and-jquery-isemptyobject/5773738#5773738

http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-a-javascript-object

http://nfriedly.com/techblog/2009/06/advancedjavascript-objects-arrays-and-array-like-objects/

http://en.wikipedia.org/wiki/Queue

http://www.bitstorm.org/weblog/2011-2/How_to_use_the_jQuery_queue_function.html

http://www.myinkblog.com/2009/09/11/sizzle-a-look-at-jquerys-new-css-selector-engine/

http://www.youtube.com/watch?v=ijpD8ePLBds

http://webhole.net/2009/11/28/how-to-read-json-with-javascript/

http://ajax.sys-con.com/node/676031

http://www.w3.org/DOM/#what

http://www.quirksmode.org/dom/intro.html

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.40.189