jQuery at dusk

Authored by James Padolsey

Reviewed by [?]

(this "book" is unfinished... enjoy!)



Copyright © James Padolsey

Creative Commons Attribution-NonCommercial-ShareAlike 3.0 unported license. You are free to remix, tweak, and build upon this work non-commercially, as long as you credit James Padolsey (the copyright holder) and license your new creations under the identical terms. Any of the above conditions can be waived if you get permission from the copyright holder. For any reuse or distribution, you must make clear to others the license terms of this work. The best way to do this is with a link to the license.

Introduction

Blah blah blah, introduction...

This short book has been written to demonstrate, discuss and divulge the stengths of jQuery and its companions, the DOM and of course, JavaScript itself. Be wary, for this isn't your normal book -- it isn't so much a stream of pretty prose as it is a meandering torrent of examples, explanations, abstract discussion and whimsical tangents.

My name is James Padolsey, and I hope this book can teach you some valuable things, and at the very least, plant seeds of curiousity that will later drive you to discover new things.

You should note that this publication assumes jQuery version 1.4 (1.4.2 to be precise). However, much of the material will still be relevant for other versions..

Contents

What you already know

You should already be an intermediate level jQuery developer.

Intermediate jQuery developer: A developer whose comfortable with jQuery and knows its API quite well. This person has authored one or two simple jQuery plugins and uses jQuery quite often to create and enhance rich user experiences.

If you don't understand something along the way, and my explanations aren't sufficiently clear, then I'm sure you'll find relevant documentation elsewhere. May I suggest: api.jquery.com as your first port of call, and for JavaScript issues you should seak refuge at the Mozilla Developer Center.

Before continuing, I suggest you go and get a cup of coffee, tea, or an apple! And maybe some popcorn, oh and a warm blanket and cup of hot chocolate... actually forget this... I'm tired...Goodnight!

Okay, what does jQuery() really do?

Everything to do with jQuery resides under an object that you can access via the "jQuery" identifer (and, of course, the dollar symbol). This object happens to be a function, and in JavaScript, functions are (specialised) objects.

jQuery is, of course, a function, but it's good to understand that it is also an object. Confused?

The jQuery function is sometimes referred to as the jQuery "wrapper" function, since it effectively wraps stuff in a jQuery instance.

Let's have a look at the source code for the function itself:

var jQuery = function( selector, context ) { return new jQuery.fn.init( selector, context ); };

The jQuery function returns an instance of the jQuery class*. jQuery.fn.init is a constructor and it will construct an object that we will refer to as the jQuery instance.

* - JavaScript has inheritance, but it's not classical inheritance; it's prototypal. So, really I shouldn't be calling it a "class". Maybe I should call it a "proto" instead...

The jQuery instance is just a regular object. It has properties, and it has methods that are inherited from jQuery's prototype ( jQuery.fn.init.prototype , or jQuery.fn for short).

We could construct a jQuery-like instance ourselves:

var myFakejQObject = { length: 2, 0: document.createElement('div'), 1: document.createElement('span'), css: function(name, value) { for (var i = 0, l = this.length; i < l; ++i) { this[i].style[name] = value; } return this; } };

The curly braces ( { and } ) are used in quite a few places in the JavaScript language. Their most common usage is to mark the beginning and end of a block statement -- that is, a collection of statements -- also known as a compound statement.



You see this all the time, for example, if(foo){ /* I'm in a block */ } or even, while(true){ /* me too */ } ...



Another common usage of the curly braces is to create an object literal -- this is what we're doing above, within 'myFakejQObject' -- an object literal is denoted by an opening curly brace, some key-value pairs and then a closing curly brace.

We've only given it one method, but it is usable:

myFakejQObject.css('color', 'red');

You'll notice that this object has a length property and some numerical properties -- it's the same deal with jQuery instances. Given these qualities we consider it an "array-like object", in that it is like an array in every way except that it's not actually an Array instance (like var realArray = [1,2,3] ).

If you have firebug installed, you can take a peak at any jQuery instance, simply by doing console.log(jQueryObject) . Let's try it:

console.log( jQuery(document) );

As discussed, there are some regular properties and a bunch of inherited methods.

Just to re-affirm: When you call jQuery() you're creating a unique instance of jQuery that can be referenced and accessed like any other object in JavaScript:

var foo = jQuery('#foo'); foo.addClass('bar');

alert(foo.selector); // alerts "#foo"

A jQuery instance is sometimes referred as a "jQuery collection". Both terms are useful depending on the context. Be aware that they are technically the same thing (i.e. the object produced by the jQuery constructor).

And, as you've probably noticed, all of jQuery's mutator methods return the instance itself to allow chaining of methods ( object.aMethod().bMethod() ...). Some accessor methods return a jQuery instance too, but it's not the same one -- it's a new one. E.g. Calling .parent() gives you a new jQuery instance; it does not modify the current instance.

A mutator method (a.k.a "modifier"/"setter"), in it's most general form, is a method that changes something within the instance. An accessor method (a.k.a "getter") is a method that returns a value, without mutating (changing) anything.

It's pretty simple to determine which jQuery methods are accessor methods. Any method that gets something for you, whether it be an attribute, a CSS property value, a data value, a specific state, or even a bunch of DOM nodes is an accessor method.

Here are some accessor methods (I've added some typical arguments too):

parent()

hasClass('foo')

attr('id')

data('foo')

is('div.foo')

find('div')

children()

closest('a')

width()

All the methods that change something on the instance, whether it be an element's html() , a new event handler, or removing a class from a bunch of elements is a mutator method. Some of jQuery's mutator methods:

addClass('foo')

removeClass('foo')

attr('id', 'foo')

data('foo', 123)

html('<a/>')

css('color','red')

click(function(){})

bind('event.namespace', function(){})

Quite a few of jQuery's methods act as mutators and accessors, depending on what arguments you pass to them. For example, with one argument, the attr method is an accessor, and with two it's a mutator.

There's the DOM, and then there's jQuery

A jQuery instance allows you to call any of jQuery's methods on a collection of elements (as discussed, each element in a jQuery instance is indexed numerically, 0, 1, 2 etc.).

jQuery's methods do their deeds by utilising the native DOM API in browsers. jQuery's API is separate to the DOM API.

When you have a jQuery instance, you can call jQuery methods. When you have a single DOM node, you can use the native DOM API, and call DOM methods and set DOM properties, but you cannot use jQuery methods on regular DOM elements.

var jQInstance = jQuery('<div/>'); jQInstance.css('color', 'red'); // Using jQuery's API to set the color var domElement = jQInstance[0]; // Acessing the first element in the collection domElement.style.color = 'blue'; // Using the DOM API to set the color

I know this may seem obvious to many of you but it's incredibly important to understand that jQuery instances are not the same as DOM nodes/elements. As mentioned, jQuery "wraps" your elements, by storing them in jQuery instances as array items (0,1,2,3)..

It's also important to keep track of what you're dealing with in your code. The following returns a jQuery instance:

jQuery('body');

And this returns a DOM element:

jQuery('body')[0];

And it follows that this returns a jQuery object:

jQuery( jQuery('body')[0] ); // Totally pointless re-wrapping of <body> element

Well, it's like an array, so...

We've established that the jQuery instance is an "array-like object", and I'll tell you now that JavaScript's Array methods are pretty leniant on what they'll accept as their context. Since the jQuery instance walks and talks like an array, we can call any array method with the jQuery instance set as the context.

You can call a function with any specified context. The context you decide on can be accessed via the this keyword within the function.

Here's a quick example.

JavaScript arrays have a sort method, which can be used in the following ways:

// ---------------------- // Regular numerical sort // ---------------------- var array = [ 123, 675, 101, 873, 324 ]; array.sort(); // => [101, 123, 324, 675, 873]; // -------------------------------------------- // You can also pass a custom sorting function: // -------------------------------------------- var array = [ [1, 2, 3], [1, 2], [1, 2, 3, 4], [1] ]; // Sort array by inner arrays' length array.sort(function(a, b){ return a.length > b.length ? 1 : -1; }); // Results in => // [ // [1], // [1, 2], // [1, 2, 3], // [1, 2, 3, 4] // ]

The sort method will sort the array according to the passed function, or, if you don't pass a function it'll sort lexicographically (in dictionary order, according to the string conversion of each item): https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/sort

Assuming the following markup:

<ul> <li>Tiger</li> <li>Dog</li> <li>Python</li> <li>Cat</li> <li>Anaconda</li> <li>Monkey</li> </ul>

We can sort the list-items into alphabetic order by employing the sort method, which can be accessed through Array.prototype :

// Give the jQuery prototype the sort method: jQuery.fn.sort = Array.prototype.sort; // Sort the list-items: var ul = jQuery('ul'); ul.children().sort(function(a,b){ return jQuery(a).text() > jQuery(b).text() ? -1 : 1; }).appendTo(ul); // re-append to parent, in the sorted order

The sort method won't sort them within the DOM, it'll merely sort each element into its correct position in the jQuery instance (i.e. the elements will end up under different indexes). To make the elements appear in their sorted order we simply need to re-insert them into the DOM (that's what the appendTo is about).

The details are not important. The point is, jQuery instances are array-like objects, and this quality is very useful. It allows us to "steal" Array methods, amongst other things.

By the way, if you're looking for a reliable "sort" plugin, check out this:

http://github.com/jamespadolsey/jQuery-Plugins/tree/master/sort/

The DOM is slow!

As you've no doubt been told multiple times, DOM operations are heavy tasks and can take a considerable amount of time to complete. jQuery is riddled with optimisations to make it all quicker but you still need to be aware of the common pitfalls.

innerHTML is ugly, but very fast

innerHTML is a property that all DOM elements have. It allows you to set the html that resides within an element. Setting an element's innerHTML will initiate the browser's HTML parser, which will form a DOM structure.

Filling an element's innerHTML is quick -- very quick! And it's even quicker if that element is outside of the document.

When you pass a string of HTML to jQuery's html() method it will simply set each element's innerHTML property to that string. jQuery does the same when you pass a string of HTML to the jQuery() function -- in this case though, it creates a temporary parent element to fill with the HTML and then gathers the produced nodes and gives them to you as a jQuery collection.

I hate to admit it, because it's quite ugly, but innerHTML is the best approach if performance is important to you (it should be).

// Not slow, but not lightning fast either: $('<div/>') .append( $('<a/>', {href:'#'}), $('<ul/>').html('<li/><li/><li/>') ); // Lightning fast: $('<div><a href="#"></a><ul><li/><li/><li/></ul></div>');

There are a few considerations to make when dynamically creating elements:

Should the HTML be defined within your JavaScript -- or should it be stored elsewhere, possibly as a template, easily retrievable by your JavaScript but not embedded within? Do you need direct references to any of the added elements, perhaps for binding event handlers? Should you really need to add large amounts of HTML? Shouldn't you be progressively enhancing what's already there?

If you're not sure what I mean by "progressively enhancing" please look up "progressive enhancement". It's a very important concept in the world of JavaScript development. Some would have you believe that it's not really that important -- don't listen to them.

The second point is often overlooked. Many people tend to take the following approach:

$('body').append('<div><a id="foo" href="#">Click</a></div>'); $('#foo').click(function(){ alert('You clicked foo!'); });

Since you're creating and adding <a id="foo"... to the DOM from the JavaScript, it would make sense to get a reference while you're doing so, instead of pointlessly selecting the element after it's been added.

var foo = $('<a id="foo" href="#">Click</a>'); foo.click(function(){ alert('You clicked foo!'); }); $('<div/>').append(foo).appendTo('body');

That's better! No expensive (and pointless) DOM selection has been made. And, even though #foo is a speedy selector, it still isn't good practice to go selecting stuff that you should have references to already.

Just to be clear, most of the time you shouldn't need to use a selector to retreieve items that you've added to the DOM. The fact that you added them means that you should have references already.

Templates

I mentioned the usage of templates. This is becoming increasingly popular. It doesn't have to be complicated -- if you just want to store a static piece of HTML, you can do so by simply hiding it in an element:

... regular content in your document ... <div id="my-template" style="display:none;"> ... this is a template, embedded in my HTML document ... <div><a id="foo" href="#">{{message}}</a></div> </div>

And then, in your JavaScript, you would access it like so:

var template = jQuery('#my-template').html(); template = template.replace('{{message}}', 'Click!'); // ... use the template

This approach should be avoided though. Firstly, the template itself isn't really content, so it shouldn't be embedded in the HTML. The template might be used to contain real content added via JavaScript but that won't be seen by less-capable browsers, people using screen-readers, and search engines. We want to make our templates unobtrusive, so that individuals with less-capable internet-surfing software (and those that are surfing without JS enabled) don't waste bandwidth by downloading templates they're not going to be able to use.

Also, if you embed any <img/> elements (or other elements with src attributes) to this hidden div, it will generate a real server request -- even if you leave the src blank, some browsers make a request!

Also, that fact that your template is in the document means that the browser has to take time to parse it, which is a huge waste considering that you're not even going to use the produced nodes -- it's likely that you'll just retreive the template as HTML and then re-inject it.

There are some other options. You could, for example, store the template in a separate file and request it via XHR (a.k.a Ajax) when required.

jQuery.get('my-template.html', function(template){ template = template.replace('{{message}}', 'Click!'); // ... use the template });

With large templates this is quite a good approach, and it's very unobtrusive -- users without JavaScript don't need to download the template.

Another popular approach for templating is to use a <script> element with a custom type (such as text/html ). E.g.

... regular content ... <script id="my-template" type="text/html"> ... this is a template, embedded in my HTML document ... <div><a id="foo" href="#">{{message}}</a></div> </script>

Specifying a custom type means it won't be interpreseted as JavaScript by the browser. It'll be left alone, and you can do what you want with it. Still though, this approach is quite obtrusive.

Templating is quite simple really. All you're doing is taking a string of HTML and replacing certain tokens with real content, such as in our example earlier:

template = template.replace('{{message}}', 'Click!');

Obviously there are more flexible/refined template engines out there, so don't feel like you have to make your own. Check out the following possibilities:

jQuery-tmpl - jQuery's own template engine -- at the time of writing this is not part of the jQuery core.

John Resig's Micro-templating snippet.

TrimPath JST

EJS

DOM Element creation - quick or elegant?

We've established that innerHTML is lightning fast, but unless you use templates, it's ugly. HTML itself is not ugly, in fact it's a pretty decent markup language (who knew?); but HTML in JavaScript really sucks and it can be hard to maintain. Have a look:

var html = '<li>Foo\'s <a href="#">Bar</a>.</li><li><a href="#" rel="internal">Banana</a></li>......';

Well, okay that doesn't look too bad, but trust me, three months later that string has grown ten-fold, and you've got the task of making each word localisable. Fun!

Using a template would be a good idea in this situation.

For smaller element-creation endeavors, jQuery gives you a succinct and elegant syntax:

// Create a <div> element with an id of "foo", // a class of "bar" and bind a mouseover event // handler to it: var divElement = jQuery('<div/>', { id: 'foo', 'class': 'bar', mouseover: function() { // eh.. } });

Easy, maintainable and a lot easier to look at than a string of HTML...

You may have noticed that I wrapped the "class" property name in quotes ( {...'class':'bar'} ) -- this is required because JavaScript considers "class" a reserved word.

The object you pass in as the second parameter to jQuery() will, for the most part, act as if you're passing it to the attr method, like so:

var divElement = jQuery('<div/>').attr({ id: 'foo', 'class': 'bar' });

jQuery does however use its own methods for certain properties. For example, the "mouseover" property maps directly to jQuery's mouseover method. The following property names are mapped over to their respective jQuery methods in the same fashion:

blur

change

click

css

data

dblclick

error

focus

focusin

focusout

height

html

keydown

keypress

keyup

load

mousedown

mousenter

mouseleave

mousemove

mouseout

mouseover

mouseup

offset

resize

scroll

select

submit

text

unload

val

width

You can access (and change) the methods that are mapped to via jQuery.attrFn .

Among other things, this means that you can safely bind event handlers during element creation, and they will be added using jQuery's robust event mechanism. Any properties that you specify that are not in the above list will be added as regular attributes (e.g. rel , title , href , id ...).

There are a few cases where I would absolutely recommend avoiding jQuery('<elem></elem>') type element creation, and that's when you need to create a bunch of similar elements from a single source, such as an array:

/* DON'T DO THIS */



var listOfFruit = ['apple','banana','melon','grape','orange','pineapple','tomato'], ul = $('<ul/>'); jQuery.each(listOfFruit, function(){ $('<li/>').text(this).appendTo(ul); });

That would produce the following DOM structure (" ul "):

<ul> <li>apple</li> <li>banana</li> <li>melon</li> <li>grape</li> <li>orange</li> <li>pineapple</li> <li>tomato</li> </ul>

The listOfFruit array is so small that it couldn't cause too much harm, but if you were dealing with an array any larger than a dozen or so items, you'd definitely want to avoid that technique.

A better solution would be to build the HTML (containing the list-items) and then append that all to the unordered-list in one go (in other words, we're rocking innerHTML !):

var listOfFruit = ['apple','banana','melon','grape','orange','pineapple','tomato'], ul = $('<ul/>'), html = ''; jQuery.each(listOfFruit, function() { html += '<li>' + this + '</li>'; }); ul.html(html);

Or, we could build an array and then join it at the end:

var listOfFruit = ['apple','banana','melon','grape','orange','pineapple','tomato'], ul = $('<ul/>'), html = []; jQuery.each(listOfFruit, function() { html.push('<li>' + this + '</li>'); }); ul.html(html.join(''));

This is slightly faster than the previous string-concatenation example, but it can still be improved:

var listOfFruit = ['apple','banana','melon','grape','orange','pineapple','tomato'], ul = $('<ul/>').html( jQuery.map(listOfFruit, function(){ return '<li>' + this + '</li>'; }).join('') );

Okay, that was just a bit of syntax sugar -- no speed enhancements there...

Now for perfection:

var listOfFruit = ['apple','banana','melon','grape','orange','pineapple','tomato'], ul = $('<ul/>').html( '<li>' + listOfFruit.join('</li><li>') + '</li>' );

Think about what's going on there. Every item in the listOfFruit array is being added to a string, and delimited by whatever you specify in the argument to the join() method:

apple

</li><li> banana </li><li> melon </li><li> grape </li><li> orange </li><li> pineapple </li><li> tomato

The result of listOfFruit.join('</li><li>') is being wrapped with '<li>' and '</li>' , producing the following string:

<li>apple</li><li>banana</li><li>melon</li><li>grape</li><li>orange</li><li>pineapple</li><li>tomato</li>

Using array.join('.. delimiting HTML ..") is simply the fastest way to build a string of HTML from an array of simple data. Follow that with the html() method and you've got one swift snippet of code.

Faster DOM manipulation

EDIT: Take this section with a spoonful of salt... At the time of writing I was still quite new to the concept of reflowing/repainting.

Inserting new elements into the DOM can be slow, but repeatidly manipulating those elements can be even slower!

The key thing to understand is that whenever you manipulate an element that's currently within the document, you're probably going to be causing either a reflow (a.k.a "layouting") or a repaint (a.k.a "redraw"). Actually, much of the time, you'll be causing both at the same time.

A reflow involves the browser having to revalidate relevant elements in the render tree by calculating their new dimensions and the dimensions of elements that follow. A repaint occurs when the browser has to recalculate how an element must appear, both geometrically (e.g. width/height/padding) and stylistically (e.g. color/opacity).

For instance, changing an element's height will cause a reflow -- the browser calculates the new position and layout of the element based on its new height, plus any surrounding elements that may be affected. The changes then need to be re-drawn to the page, and this is what we call a repaint.

Given what we know about reflowing and repainting it makes perfect sense that any DOM operation is significantly faster with elements outside of the document, or even within hidden elements*. If an element is hidden or is not within the document, the browser needn't bother to reflow or repaint, as no changes (other than un-hiding/un-removing it) can possibly effect what the user sees. Note that, upon hiding/removing an element, usually at least one reflow and repaint must occur, since the removal of that element is likely to affect the appearance of the render.

* - Not all browsers behave as you would expect with hidden elements (src). Given the unfortunate variegation it's best to simply remove the element from the document instead of just hiding it with display:none; -- you might also consider using a document fragment -- this will be discussed.

// VERY GOOD - manipulate before adding to the DOM jQuery('<div/>').css('color','red').appendTo('body'); // GOOD, BUT NOT GREAT - manipulate after adding to the DOM jQuery('<div/>').appendTo('body').css('color','red');

You may think it foolish to care about minor optimisations like these, even pointless, seeing as we're operating on top of a fair bit of abstraction (jQuery), but let me assure you that these optimisations can make a significant difference -- and, at the very least, they're good to know about.

Should you refactor all of your code to make sure that you're manipulating before "appending"? -- No! That would be quite foolish and probably wouldn't make much difference. This kind of optimisation only becomes important when you're doing something over-and-over and it's causing a noticable lag/freeze on the page. As Thomas Fuchs would say, "Do not, ever, optimize prematurely"!

Moving on. As I mentioned earlier, you can speed up manipulation (or any other action that would normally instigate a reflow/repaint) by removing the element from the document beforehand. It sounds like quite a destructive action but it's actually pretty simple -- the element itself isn't being "destroyed"; it's merely being removed as a child of its current parent node, and the element object stays perfectly intact. The "raw" DOM way of removing a node is:

element.parentNode.removeChild(element);

jQuery gives us remove and detach :

jQuery(element).remove(); // Removes element + all events and data bound to element jQuery(element).detach(); // Removes element, and doesn't touch the data/events

Any event handlers or data (e.g. $(elem).data('foo',123) ) that you have bound to the element will be destroyed when using the remove method -- if you don't want this then use the aptly named detach method, which acts in exactly the same way as element.parentNode.removeChild(element) .

Once an element is removed it can be manipulated in exactly the same manner as before, except for a few obvious differences. For one, it's not in a document, so methods like parent , prev and next are pretty useless, unless you're operating within a child of the removed element, in which case everything is normal.

Also note that retrieval of an element's geometric or stylistic properties will mostly fail -- since the element is not within the document, it has no visual characteristics.

Here's a quick example. We need to construct a plugin that can speedily shuffle a list of arbitrary length:

jQuery.fn.shuffleChildren = (function(){ function fisherYatesShuffle(arr) { // Fisher-Yates shuffle has been proven // to be more random than the conventional // arr.sort(function(){return Math.random()-.5}) // http://www.robweir.com/blog/2010/02/microsoft-random-browser-ballot.html var i = arr.length, r, tempI, tempR; if ( i === 0 ) { return arr; } while ( i-- ) { // Generate random index: r = Math.floor(Math.random() * (i + 1)); // Shuffle: tempI = arr[i]; tempR = arr[r]; arr[i] = tempR; arr[r] = tempI; } return arr; } return function(doQuick) { return this.each(function(){ var container = jQuery(this), parentNode = this.parentNode, nextSibling = this.nextSibling; if (doQuick) { // Remove from document container.detach(); } // Append shuffled children container.append( fisherYatesShuffle(container.children()) ); if (doQuick) { // Insert at the correct location in the document parentNode.insertBefore(container[0], nextSibling); } }); }; })();

It's a bit of a hefty plugin, but it's important that we do it properly. As mentioned in the comments, we're using the Fisher-Yates shuffle because it's been proven to be more random than more conventional techniques.

You'll notice that I've added a "doQuick" flag as a parameter -- this is just to make testing a bit easier. We can generate a quick test to determine how many milliseconds we've shaved off by removing the element from the document:

function test(fn, times) { var i = -1, d = +new Date; while ( ++i < times ) { fn(); } return +new Date - d; } var list = jQuery('<ul/>')

.append('<li>' + Array(500).join('</li><li>') + '</li>')

.appendTo(document.body); // We're testing the shuffle 5 times on each configuration var withQuick = test(function(){ list.shuffleChildren(true); }, 5); var withoutQuick = test(function(){ list.shuffleChildren(); }, 5); alert( 'Element removed from document: ' + withQuick + '

' + 'Element not removed from document: ' + withoutQuick );

The results range a lot between browsers. IE, as usual, is either spot on or totally bonkers. The results, on average (smaller numbers are better):

Removed Not removed Firefox 3.6 193 267 Opera 10.10 428 450 IE 8 532 515 Chrome 4.1 191 264

Before we even think about the results, we should consider what should be happening here.

Removing the container and then re-appending it could cause two sets of reflows/repaints in itself - simply because the browser has to re-calculate how the page will render each time.

If we leave everything in the document, then multiple reflows/repaints will occur as we're shuffling elements (many elements are getting re-appended), but interestingly, this may not be the case. Browsers will, when they can, queue up changes and apply them in bulk so that only one reflow and repaint needs to occur. This may be what accounts for Opera's and IE's behaviour, although there may be something else going on there.

More information about reflow/repaint and the inherent performance concerns:

Unfortunately this is quite a new area of enquiry for front-end developers and there isn't a great deal of information available on it and how different browsers behave. Regardless, it's still an important concept, and one that we can use to make our applications and websites faster. I suggest reading the linked articles -- I could write more but I think it's best for you to read first-hand the difficulties that this presents, after all, much can be lost in translation.

Document fragments

A document fragment is, for all intents and purposes, a container for DOM nodes. It's similar to a regular DOM element but has a few special qualities.

We can create a document fragment like so:

var frag = document.createDocumentFragment();

A document fragment can be appended to just like a regular element:

frag.appendChild(document.createElement('div'));

Notice that we're not using jQuery here, just native DOM methods. jQuery doesn't really have support for document fragments, but that's no problem -- they're incredibly simple to use.

The really great thing about document fragments is that you can append all of their content to another element or document fragment in one swift operation.

// Add some DIVs frag.appendChild(document.createElement('div')); frag.appendChild(document.createElement('div')); frag.appendChild(document.createElement('div')); document.body.appendChild(frag); // Add all the DIVs to the body, at once!

When appending a fragment, you're actually appending whatever nodes it contains. The fragment itself is just an abstract container for arbitrary nodes, nothing more.

Document fragments behave much like regular DOM elements (e.g. document.createElement('div') ), except for a couple of crucial differences. For one, document fragments don't have an innerHTML property, so the only way to get elements inside a fragment is to use the native appendChild and insertBefore methods. Obviously you can append a regular element and then use innerHTML on that, but the fragment itself does not have innerHTML .

Document fragments can aid in our fight against document reflow and repaint. They're excellent for accommodating off-document

...

Abstraction is King!

Abstraction is a central topic in programming -- it's everywhere, you can't avoid it! jQuery itself is one massive abstraction, sitting on top of another massive abstraction, the DOM.

In computer science, the mechanism and practice of abstraction reduce and factor out details so that one can focus on a few concepts at a time.

en.wikipedia.org/wiki/Abstraction_(computer_science)

To re-iterate: abstraction is the means via which we can forget about the details of an implementation and simply focus on our concerns.

Your jQuery code should provide further abstractions, and it's important to create meaningful and expressive abstractions so that your code is readable, well-structured and maintainable.

Every time you define a function you're abstracting a piece of logic:

function sayHello() { $('<p>Hello</p>').appendTo('body'); }

That function is an abstraction of the logic involved in creating a new paragraph in the document that contains the word "Hello".

Object-orientated programming is a technique used to create abstractions of the real world in programming languages. If we take a well-known object, such as a person, we can summarize its main properties and functions like so:

function Person(name) { this.name = name; this.dateOfBirth = new Date(); } Person.prototype.eat = function() { // eat... }; Person.prototype.sleep = function() { // sleep... };

You get the idea...

Before we continue, I think some clarification is in order: Strictly speaking, pretty much everything in JavaScript is object-orientated (after all, everything is an object), but when I say "object-orientated" in this chapter I'm specifically talking about the technique shown above -- creating an abstract representation of an object that can be instantiated multiple times. E.g.

var jim = new Person('Jim'); var karan = new Person('Karan');

We can use this technique with a more applicable object, such as a slide-show.

(ok... this is where I got bored... meh...)