You are on page 1of 37

jQuery Internals

+ Cool Stuff
John Resig
http://ejohn.org/ - http://twitter.com/jeresig/
Overview
✦ Why we do what we do
✦ Features you may not know about
✦ New features coming
Parts of jQuery
✦ Common
✦ Selectors
✦ DOM Modification
✦ Events
✦ Sniffing
Chaining
✦ jQuery("<li><a></a></li>") // li
.find("a") // a
.attr("href", "http://ejohn.org/") // a
.html("John Resig") // a
.end() // li
.appendTo("ul");

✦ jQuery("<li><a></a></li>") // li
.find("a") // a
.attr("href", "http://ejohn.org/") // a
.html("John Resig") // a
.andSelf() // li, a
.addClass(“person”) // li, a
.end() // a
.end() // li
.appendTo("ul");
Isolation
✦ jQuery shouldn’t affect outside code
✦ We’re good at this

✦ Outside code shouldn’t effect jQuery


✦ Getting better at this
✦ (Still hurt by Object.prototype)
jQuery Wrapper
✦ (function(){
var jQuery = window.jQuery = function(){
// ...
};
})();
✦ (function(){
var foo = 5;

})();
Plugin Wrapping
✦ (function($){
// Your code...
})(jQuery);
✦ (function(){
var $ = jQuery;
// Your code...
})();
noConflict
✦ // Remove $
var $jq = jQuery.noConflict();
✦ // Remove $ and jQuery
jQuery.noConflict(true);
✦ Can even have multiple copies of jQuery
on the page, simultaneously
noConflict
✦ (function(){
var oldjQuery = window.jQuery;
var jQuery = window.jQuery = function(){
// ...
};
jQuery.noConflict = function(all){
if ( all )
window.jQuery = oldjQuery;
return jQuery;
};
})();
Element Data
✦ Added in jQuery 1.2
✦ Attaching data to elements can be
hazardous
✦ Store data:
jQuery.data(elem, “name”, “value”);
✦ Read data:
jQuery.data(elem, “name”);
✦ All data is stored in a central cache and
completely garbage collected, as necessary
Element Data (cont.)
✦ Added in jQuery 1.2.3
✦ Can handle namespacing
$(”div”).data(”test”, “original”);
$(”div”).data(”test.plugin”, “new data”);
$(”div”).data(”test”) == “original”; // true
$(”div”).data(”test.plugin”) == “new data”; // true
✦ Advanced data handling can be overridden
by plugins
$(element).bind(”setData.draggable”, function(event, key, value){
self.options[key] = value;
}).bind(”getData.draggable”, function(event, key){
return self.options[key];
});
Selectors
How It Works
✦ How it currently works
✦ “div > p”
✦ Find all divs
Loop through each div
✦ Find all child elements
✦ Verify if element is paragraph
How It Works
✦ “div p”
✦ Find all divs
Loop through all divs
✦ Find all p, relative to the div

✦ Merge all results


✦ Figure out unique results
Sizzle
✦ http://github.com/jeresig/sizzle/tree/master
✦ New Selector Engine for jQuery
✦ 1.5 - 4x faster than other libraries
✦ 4KB Compressed
✦ No dependencies, can be used by other
libraries (MochiKit, Prototype)
How Does it Work?
✦ Query Restructuring
✦ “div p”
✦ Find all p elements
For each p element
✦ check if parent is div
✦ if not, traverse up farther
✦ if at top, remove element
✦ if so, save element

✦ No merging! No unique!
How Does it Work?
✦ Faster for some queries, slower for others
✦ Depends on the DOM structure
✦ “div > p” much faster, for example
✦ Built like how browsers query the DOM
Niceties
✦ Query Caching
✦ if ( document.addEventListener && !document.querySelectorAll ) {
cache = {};
function invalidate(){ cache = {}; }
document.addEventListener("DOMAttrModified", invalidate, false);
document.addEventListener("DOMNodeInserted", invalidate, false);
document.addEventListener("DOMNodeRemoved", invalidate, false);
}

✦ Smart Fallbacks
✦ if ( document.getElementsByClassName ) {
Expr.order.splice(1, 0, "CLASS");
Expr.find.CLASS = function(match, context) {
return context.getElementsByClassName(match[1]);
};
}
Manipulation
✦ Four common methods:
append, prepend, before, after
✦ $(“<li>and this too!</li>”)
✦ How does it work?
3-step Process
✦ Cleaning the input
✦ Converting it into a DOM
✦ Injecting it into the DOM
Cleaning
✦ Make sure we’re working with HTML
input
✦ (Convert XML to HTML)
✦ <table/> -> <table></table>
✦ elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front,
tag){
return tag.match(/^(abbr|br|col|img|input|link|meta|param|
hr|area|embed)$/i) ?
all :
front + "></" + tag + ">";
});
Converting
✦ Inject HTML string using innerHTML
✦ var div = document.createElement(“div”);
div.innerHTML = html;
div.childNodes; // Your meat!
✦ But doesn’t work for all HTML
✦ <tr>, <td>, <option>, <legend> (+ others)
must be in correct container elements
✦ “<table><tbody>” + html + “</tbody></
table>”
Injecting
✦ var elems = div.childNodes;
✦ Loop through elems, cloneNode(true)
each, insert into DOM
✦ 5 paragraphs
✦ 100 divs
✦ 2 method calls (insert, clone)
✦ 1000 method

✦ *Very* slow
✦ Simple plugin provides 10-15x speed-up:
http://dev.jquery.com/~john/ticket/append/
Document Fragments
✦ No div.childNodes looping
✦ Move the nodes into a Document
Fragment
✦ Husk DOM container
✦ Whole container can be cloned
✦ and whole container can be injected
✦ Saves a ton of repetition
Events
Non-DOM Events
✦ function User(){}
✦ var user = new User();
✦ $(user).bind(“login”, function(){
alert(“all done”);
});

$(user).trigger(“login”);
Namespaced Events
✦ Added in jQuery 1.2
✦ Targeted adding and removal of events
✦ $(“div”).bind(“click.foo”, function(){
alert(“foo!”);
});
✦ Time to clean up!
$(“div”).unbind(“click.foo”);
✦ Added in jQuery 1.2.3:
$(“div”).unbind(“.foo”);
Special Events
✦ Added in jQuery 1.2.2
✦ Can create whole shadow event system
✦ New events: mouseenter, mouseleave,
mousewheel (w/ plugin), ready
✦ $(”li”).bind(”mouseenter”, function(){
$(this).addClass(”hover”);
}).bind(”mouseleave”, function(){
$(this).removeClass(”hover”);
});
Animations
✦ Full Animation plugin (in jQuery 1.2):
✦ jQuery.fx.step.corner = function(fx) {
fx.elem.style.top = fx.now + fx.unit;
fx.elem.style.left = fx.now + fx.unit;
};
✦ $(”#go”).click(function(){
$(”#block”).animate({corner: ‘40px’}, 500);
});
Sniffing
✦ All major JS libraries use browser sniffing
✦ Look at the user agent and make guesses
✦ We can get rid of this!
✦ Makes our code more resilient to change
Testing & Analysis
Testing
✦ Rapid testing
✦ ./gen.sh
#!/bin/sh
svn co https://jqueryjs.googlecode.com/svn/trunk/jquery $1
&> /dev/null
cp $2.html $1/index.html
cd $1
make &> /dev/null

✦ ./gen.sh 1234 dom


Test Suite
✦ qUnit (jQuery Test Suite)
http://docs.jquery.com/QUnit
✦ By Joern Zaefferer
qUnit Usage
✦ test("a basic test example", function() {
ok( true, "this test is fine" );
var value = "hello";
equals( "hello", value, "We expect value to be hello" );
});

module("Module A");
test("first test within module", function() {
ok( true, "all pass" );
});
test("second test within module", function() {
ok( true, "all pass" );
});

module("Module B");
test("some other test", function() {
expect(1);
ok( true, "well" );
});
qUnit Output
Profiling
✦ Deep Profiling Plugin
✦ Watch all method calls and events
✦ http://ejohn.org/blog/deep-profiling-
jquery-apps/
✦ http://dev.jquery.com/~john/plugins/profile/
github.com.html
✦ javascript:jQuery.displayProfile();
Thank You!
✦ John Resig
✦ http://ejohn.org/
✦ http://twitter.com/jeresig/

You might also like