14 Days of jQuery

An online event marking the release of jQuery 1.4. To celebrate, we're unveiling 14 releases over a period of 14 days.

jQuery 1.4

Today's News

jQuery 1.4 Released - Full Release Notes

14 Days of jQuery: 15 Days of Prizes. Submit your cool uses of jQuery, win a laptop and hosting!

In celebration of jQuery’s 4th birthday, the jQuery team is pleased to release the latest major release of the jQuery JavaScript library! A lot of coding, testing, and documenting has gone into this release, and we’re really quite proud of it.

I want to personally thank Brandon Aaron, Ben Alman, Louis-Rémi Babe, Ariel Flesler, Paul Irish, Robert Katić, Yehuda Katz, Dave Methvin, Justin Meyer, Karl Swedberg, and Aaron Quint who put a lot of work into fixing bugs and getting the release out the door.

Downloading

As usual, we provide two copies of jQuery, one minified (we now use the Google Closure Compiler as the default minifier) and one uncompressed (for debugging or reading).

NOTE: jQuery 1.4.1 has already been released. Please use that instead of the 1.4 release.

Additionally, Google has provided us with a copy of jQuery hosted on their servers. This copy of jQuery is automatically minified and gzipped – and served from Google’s fast edge cache servers.

You can feel free to include the above URL directly into your site and you will get the full performance benefits of a quickly-loading jQuery.

With jQuery 1.4 we attempted to minimize any large upgrade hassles – maintaining the signatures of all public functions. That being said, please read through the list of potentially-breaking changes to be aware of what might cause problems in your applications.

Features

Below is an overview of all the changes and functionality added to jQuery 1.4. Additionally all of the changes have been documented in the jQuery 1.4 docs.

Performance Overhaul of Popular Methods

Many of the most popular and commonly used jQuery methods have seen a significant rewrite in jQuery 1.4. When analyzing the code base we found that we were able to make some significant performance gains by comparing jQuery against itself: Seeing how many internal function calls were being made and to work to reduce the complexity of the code base.

# of Function Calls for Popular jQuery Methods
View the cropped chart.

In jQuery 1.4 we’ve significantly reduced the complexity of the most popular methods in jQuery. The full performance details can be found below.

Easy Setter Functions

For a while now, you’ve been able to pass a function into .attr() and the return value of that function is set into the appropriate attribute. This functionalilty has now been extended into all setter methods: .css(), .attr(), .val(), .html(), .text(), .append(), .prepend(), .before(), .after(), .replaceWith(), .wrap(), .wrapInner(), .offset(), .addClass(), .removeClass(), and .toggleClass().

Addtionally, for the following options, the current value of the item is passed into the function as the second argument: .css(), .attr(), .val(), .html(), .text(), .append(), .prepend(), .offset(), .addClass(), .removeClass(), and .toggleClass().

This enables code like:

// find all ampersands in A's and wrap with a span
$('a').html(function(i,html){
  return html.replace(/&amp;/gi,'<span class="amp">&amp;</span>');
});
 
// Add some information to the title of the anchors
$('a[target]').attr("title", function(i,title){
  return title + " (Opens in External Window)";
});

Ajax

Nested param serialization (jQuery.param() Documentation, Commit 1, Commit 2)

jQuery 1.4 adds support for nested param serialization in jQuery.param, using the approach popularized by PHP, and supported by Ruby on Rails. For instance, {foo: ["bar", "baz"]} will be serialized as “foo[]=bar&foo[]=baz”.

In jQuery 1.3, {foo: ["bar", "baz"]} was serialized as “foo=bar&foo=baz”. However, there was no way to encode a single-element Array using this approach. If you need the old behavior, you can turn it back on by setting the traditional Ajax setting (globally via jQuery.ajaxSettings.traditional or on a case-by-case basis via the traditional flag).

There are three ways to enable the traditional way of serialization:

// Enables for all serialization
jQuery.ajaxSettings.traditional = true;
 
// Enables for a single serialization
jQuery.param( stuff, true );
 
// Enables for a single Ajax requeset
$.ajax({ data: stuff, traditional: true });

More information: jQuery.param() Documentation, jQuery.ajax() Documentation, Commit, Code

JSON and script types auto-detected by content-type (jQuery.ajax Documentation, Commit 1, Commit 2)

If the response to an Ajax request is returned with a JSON mime type (application/json), the dataType defaults to “json” (if no dataType is specified). Additionally, if the response to an Ajax request is returned with a JavaScript mime type (text/javascript or application/x-javascript) , the dataType defaults to “script” (if no dataType is specified), causing the script to automatically execute.

Etag support has been added (jQuery.ajax() Documentation, Commit)

By default, jQuery ignores the Last-Modified header for Ajax requests, preferring to make request and ignore the browser cache. Specifying ifModified: true causes jQuery to use the browser cache if available. jQuery 1.4 will also send the If-None-Match header (for ETag support) if you specify ifModified.

Strict JSON parsing, using native JSON.parse (jQuery.ajax() Documentation, Commit 1, Commit 2, Commit 3)

jQuery 1.3 and earlier used JavaScript’s eval to evaluate incoming JSON. jQuery 1.4 uses the native JSON parser if available. It also validates incoming JSON for validity, so malformed JSON (for instance {foo: "bar"}) will be rejected by jQuery in jQuery.getJSON and when specifying “json” as the dataType of an Ajax request.

Serialize HTML5 elements (jQuery.param() Documentation, Commit)

The new HTML5 input types (such as `datetime` and `range`) will be included when you .serialize() a form.

Context for Ajax Request (jQuery.ajax() Documentation, Commit)

You can now specify a context for an Ajax request, and all callbacks will have that context set (allowing you to simplify your code and possibly avoid having to use closures, or use other objects).

jQuery.ajax({
    url: "test.html",
    context: document.body,
    success: function(){
        jQuery(this).addClass("done");
    }
});

Success callback receives XHR object as third argument (jQuery.ajax() Documentation, Commit)

The success callback for any ajax request now receives the XMLHttpRequest object as the third argument. Previously this XHR object was only accessible as the return value for $.ajax and the like.

Explicitly set a content-type (jQuery.ajax() Documentation, Commit)

In jQuery 1.3, the contentType setting was ignored in jQuery.ajax if no data was sent. In jQuery 1.4, the contentType is always sent. This fixes an issue with some backends that used the Content-Type header to decide what kind of response to send.

Explicitly specify a JSONP callback name (jQuery.ajax Documentation, Commit)

You can now specify the name of the JSONP callback in jQuery.ajax() using the jsonpCallback option.

Avoid pre-flighting cross-domain XHR (Commit)

Cross-domain ajax (for the browsers that support it) is smoother with jQuery as preflighting is avoided by default.

jQuery.ajax() is now using onreadystatechange instead of a timer (Commit)

Ajax requests should now take fewer resources by using onreadystatechange instead of polling.

Attributes

The performance of .css() and .attr() has been improved.

Performance of .css() and .attr()

The .attr() takes a function setter (.attr() Documentation)

Not only can you use a function with .attr(), but you can also use the current value of the attribute with the function.

jQuery('<img src="enter.png" alt="enter your name" />')
.attr("alt", function(index, value) {
    return "Please, " + value;
});

.val( Function ) (.val() Documentation)

<input class="food" type="text" />
<input class="food" type="text" />
jQuery("input:text.food").hide();
 
jQuery("&lt;ul class='sortable'&gt;
 
	<li>Peanut Butter&lt;/li&gt;&lt;li&gt;Jelly&lt;/li&gt;&lt;/ul&gt;")
  .sortable()
  .bind("endsort", function() {
    $(":text.food").val(function() {
      return $("ul.sortable li:eq(" + $(this).attr("data-index")  + ")").text();
    });
  });</li>

.text() works on text and CDATA nodes (.text() Documentation, Commit)

Core

Quick Element Construction (jQuery() Documentation, Commit)

When you create a single element with the jQuery function, you can now pass in an object to add attributes and events at the same time:

jQuery("
 
<div>", {
    id: "foo",
    css: {
        height: "50px",
        width: "50px",
        color: "blue",
        backgroundColor: "#ccc"
    },
    click: function() {
       $(this).css("backgroundColor", "red");
    }
}).appendTo("body");</div>

The keys of the object are functions that will be called with each value passed as an argument.

.eq(-N), .get(-N) (.eq() Documentation, .get() Documentation, Commit)

You can now pass in negative numbers for .get() and .eq(). For example, you can select the second-to-last div or, you can access the DOM element for the same:

$("div").eq(-2);
$("div").get(-2);

New .first() and .last() methods (.first() Documentation, .last() Documentation, Commit)

For convenience, .first() and .last() are aliases of .eq(0) and .eq(-1).

New .toArray() method (.toArray() Documentation, Commit)

.get() has historically returned an Array from the jQuery set. For further clarity, you can use .toArray() to achieve the same thing in jQuery 1.4. Unlike, .get(), however, .toArray() does not take an argument.

jQuery() returns empty set (jQuery() Documentation, Commit)

In jQuery 1.3, jQuery() returned a jQuery set containing just the document. in jQuery 1.4, it returns an empty jQuery set. This can be useful for creating an empty set and adding elements to it dynamically. Note: The jQuery().ready() technique still works in 1.4 but it has been deprecated. Please use either jQuery(document).ready() or jQuery(function(){}).

jQuery(“TAG”) (Element Selector Documentation, Commit)

A faster path is used when passing in a single tag name.

jQuery(“<div>”) jQuery(“<div/>”) and jQuery(“<div></div>”) (jQuery() Documentation, Commit)

All three now use the same code path (using document.createElement), improving performance for jQuery("<div></div>"). Note that if you specify attributes, we use the browser’s native parsing (using innerHTML).

CSS

The performance of the .css() method has seen a 2x performance improvement.

Performance of .css()

The performance of the .addClass(), .removeClass(), and .hasClass() methods has seen a 3x performance improvement.

Performance of addClass, removeClass, and hasClass

.toggleClass() can toggle multiple classes (.toggleClass() Documentation, Commit)

You can now call .toggleClass() with multiple selectors and they will all be toggled.

$("div").toggleClass("current active");

Data

.data() returns Object and .data(Object) sets the object (.data() Documentation, Commit 1, Commit 2)

It is sometimes desirable to work with the data attached to an element as a complete object. A common example would be wanting to copy the entire data from one element to another. In jQuery 1.4, .data() with no parameter returns the entire object, and .data(Object) sets the object. Keep in mind that this object includes events bound to the element, so use caution.

Data cache is no longer created if it isn’t needed (Commit 1, Commit 2, Commit 3)

jQuery uses a unique expando on DOM elements that is used to get the .data() for a particular element. jQuery now avoids creating that expando when data is looked up but no data has been added. This potentially increases performance and avoids polluting the DOM in these cases.

Effects

Per-property Easing (Per-property Easing Documentation, Commit)

In addition to being able to specify an easing function for an animation you can now specify an easing animation for individual properties. James Padolsey has more information and demos in his blog post.

$("#clickme").click(function() {
  $("div").animate({
    width: ["+=200px", "swing"],
    height: ["+=50px", "linear"],
  }, 2000, function() {
      $(this).after("
 
<div>Animation complete.</div>
 
 
");
  });
});

Events

New Method: jQuery.proxy() (jQuery.proxy() Documenation, Commit 1, Commit 2)

If you want to ensure that “this” inside a function will be permanently bound to a particular value, you can use jQuery.proxy to return a new function with that scope.

var obj = {
  name: "John",
  test: function() {
    alert( this.name );
    $("#test").unbind("click", obj.test);
  }
};
 
$("#test").click( jQuery.proxy( obj, "test" ) );

Event Multi-binding (.bind() Documentation)

You can now pass an object of many events to bind to an element.

$("div.test").bind({
  click: function(){
    $(this).addClass("active");
  },
  mouseenter: function(){
    $(this).addClass("inside");
  },
  mouseleave: function(){
    $(this).removeClass("inside");
  }
});

`change` and `submit` events normalized (Change Documentation, Submit Documentation)

The change and submit events work reliably across browsers for both normal and live events. We override the normal change and submit events in Internet Explorer and replace them with events that work identically to the other browsers.

New events: `focusin` and `focusout` (.focusin() Documentation, .focusout() Documentation, Commit)

focusin and focusout are generally equivalent to focus and blur but bubble, which helps tremendously if you are writing your own event delegation behavior. Please note that `focus` and `blur` will not work with the live() method; this was a design decision due to the DOM Events spec defining focus/blur do not bubble.

$("form").focusout(function(event) {
    var tgt = event.target;
    if (tgt.nodeName == "INPUT" &amp;&amp; !tgt.value) {
        $(tgt).after("<span>nothing here</span>");
    }
});

All Events Can Be Live Events (.live() Documentation)

With the exception of ready, focus (use focusin instead), and blur (use focusout instead), all events that can be bound using .bind() can also be live events.

We’re very proud to count some addtional events amongst those supported by live(). 1.4 introduces cross-browser support for
change, submit, focusin, focusout, mouseenter, and mouseleave via the event delegation in .live().

Note that if you need a live focus event, you should use focusin and focusout rather than focus and blur, because, as mentioned, focus and blur do not bubble.

Also, live() also now accepts a data object, just as bind() has. (Commit)

live/die now work with context (Commit)

You can now specify a context to the selector that will be used to bind a live event. If you do, only elements under that context will be bound. While the elements themselves do not need to exist when you create the live event, the context must exist.

Make sure ready event has body at least (Commit)

jQuery now checks to see whether the body exists, and falls back to polling for the body if it does not.

Unload is sped up in non-IE browsers that don’t need memory leak hand-holding. (Commit)

Manipulation

A number of DOM manipulation methods have seen dramatic overhauls in performance in jQuery 1.4.

Performance of .append(), .prepend(), .before(), and .after() has been improved.

Performance of DOM Insertion

Performance of .html() has been improved by nearly 3x.

Performance of .html()

Performance of .remove() and .empty() has seen over a 4x speed increase.

Performance of .remove() and .empty()

New Method: .detach() (.detach() Documentation, Commit)

detach() removes an element from the DOM but does not remove the associated event handlers. This is appropriate for temporarily removing an element to manipulate and then return.

var foo = $("#foo").click(function() {
    // do something
});
foo.detach();
// foo retains event handlers
foo.appendTo("body");

New unwrap() method (documentation, commit)

The new unwrap method will take the children of a given parent and replace said parent with them. Like so:

 
<div>
 
annie
 
davey
 
stevie</div>
$('div').unwrap();
 
annie
 
davey
 
stevie

Caching in domManip (commit)

jQuery caches the resulting nodes created using methods like jQuery("<div>") and .after("<div>"). This results in significantly faster performance on pages that do DOM manipulation with strings using these methods.

before, after, replaceWith on disconnected nodes (commit)

You can now use before, after, and replaceWith on nodes that are not attached to the DOM. This allows you to do more complex manipulations before inserting the final structure into the DOM. This also prevents reflows from occuring while the manipulation is taking place.

jQuery("
 
<div>").before("
 
Hello
 
").appendTo("body")</div>

.clone(true) also clones data (documentation, commit)

In jQuery 1.3, .clone(true) did a deep clone, but did not clone data. In jQuery 1.4, it clones data, which means that events are cloned as well. This uses the same semantics as jQuery.extend, so plain objects and Arrays are cloned, while custom objects are not.

Offset

.offset( coords | Function ) (.offset() documentation, commit)

It is now possible to set the offset of an element. Offset, like all setter methods, can now also accept a function as a second argument.

Queueing

Queueing has undergone an overhaul, improving the experience of working with queues other than the default fx.

New .delay() method (.delay() documentation, commit)

The .delay() method will delay any further elements in the queue for the specified number of milliseconds. By default, it will use the fx queue. You can specify an alternate queue as an optional second parameter to the delay function.

$("div").fadeIn().delay(4000).fadeOut();

Queue next (.queue() documentation, commit)

In jQuery 1.4 the function that’s called is passed in another function, as the first argument, that when called automatically dequeues the next item and keeps the queue moving.

jQuery("div").queue("ajax", function(next) {
  var self = this;
  jQuery.getJSON("/update", function(json) {
    $(self).html(json.text);
    next();
  };
}).queue("ajax", function() {
  $(this).fadeIn();
});

.clearQueue() (documentation, commit)

Queues can now be cleared. This will remove any unexecuted functions from the queue, but not stop running functions. Using .clearQueue() without any parameters will clear the fx queue.

Selectors

“#id p” is faster (commit) Any selector string that begins with an ID has an optimization to grab that immediately. ID rooted selectors will always be fastest.

Traversing

.index(), .index(String) (documentation, commit)

The .index() method has been rewritten to be more far more intuitive and flexible.

You can now get the index of an element in relation to its siblings:

// get the index of the first
 
	<li class="index"> in relation to its siblings:
$("li.current").index()</li>

You can get the index of an element in relation to to the current jQuery collection by passing in a selector or DOM element:

// get the index of the
 
<h3 id="more-info"> in relation to all</h3>
<h3> elements:
$("#more-info").index("h3")</h3>

New .has() method (documentation, commit)

This is a method form of the :has() filter. It takes a given jQuery set and returns all of the same elements that contain a given selector.

New .nextUntil(), .prevUntil(), .parentsUntil() methods (.nextUntil() documentation, .prevUntil() documentation, .parentsUntil() documentation, commit)

The new “until” methods function similarly to .nextAll(), .prevAll(), .parents(), but the first argument they take is a selector that will terminate the traversal.

.add(String, Element) (.add() documentation, commit)
The .add() now accepts a context. This is primarily useful in a chain when you want to add in addtional elements (returned from an ajax request, for example) and then manipulate those in addition to the others.

.closest(filter, DOMElement) (.closest() documentation, commit)

The closest method can now accept a context DOMElement as a second argument. Passing in a context will typically make your closest() calls much faster. This also applies to live() which leverages closest() internally.

Utilities

jQuery.isEmptyObject() (jQuery.isEmptyObject() documentation, commit)

This returns true if there are not any properties on the object. You can only pass in objects to jQuery.isEmptyObject(), because jQuery performs an iteration on the object that is passed in without any other checks.

jQuery.isPlainObject() (jQuery.isPlainObject(), commit )

jQuery.isPlainObject() returns true if the object is an object literal and false if the object is another kind of object or a primitive.

jQuery.contains() (jQuery.contains() documentation, commit)

jQuery.contains() returns true if both parameters are DOM nodes and the second parameter is contained inside the first.

jQuery.noop (jQuery.noop() documentation, commit)

jQuery.noop is empty function that can be used where a function is required.

jQuery.unique() (jQuery.unique() documentation)

In jQuery 1.4, the jQuery.unique() method, which is used internally in the creation of the jQuery set, always returns results in document order. This means that jQuery sets returned from jQuery functions should be returned in document order.

Miscellaneous

jQuery.browser is now engine-centric (jQuery.browser documentation, commit)

For example, you can now test for Webkit with jQuery.browser.webkit.

Better support for applets (commit 1, commit 2)

jQuery no longer attempts to bind events or data to Java applets (which throw exceptions).

No longer use arguments.callee (commit)

For compliance with Caja and because it is slated to be deprecated in the upcoming ECMAScript 5 specification, we have removed all references to arguments.callee in jQuery core.

Now use Closure Compiler instead of YUI Min (commit)

Internal Reorganization

One of the major pushes that we made with 1.4 was towards building a more legible, understandable, code base. To achieve that we did some major restructuring of the of the code base internals and began to establish some style guidelines for the code base.

Some of the major changes that were made:

  • The old ‘core.js’ file has been split apart into ‘attribute.js’, ‘css.js’, ‘data.js’, ‘manipulation.js’, ‘traversing.js’, and ‘queue.js’.
  • The ready event has been moved into core.js (as it’s a fundamental part of jQuery itself).
  • The majority of core matches the new jQuery Core Style Guidelines.
  • The logic for css and attributes have been split and aren’t so intertwined anymore.

Testing

In jQuery 1.4 we’ve fixed 207 bugs (compared to 97 bugs in the 1.3 release).

Additionally we’ve increased our test coverage from 1504 tests in jQuery 1.3.2 to 3060 tests in jQuery 1.4.

The jQuery test suite is 100% passing in all the major browsers (Safari 3.2, Safari 4, Firefox 2, Firefox 3, Firefox 3.5, IE 6, IE 7, IE 8, Opera 10.10, and Chrome).

jQuery 1.4 Test Run

Backwards-Incompatible Changes

With jQuery 1.4 we attempted to minimize any large upgrade hassles – maintaining the signatures of all public functions. That being said, please read through the following list to be aware of what might cause problems in your applications.

  • .add() no longer plainly concatenates the results together, the results are merged and then sorted in document order.
  • .clone(true) now copies events AND data instead of just events.
  • jQuery.data(elem) no longer returns an id, it returns the element’s object cache instead.
  • jQuery() (with no arguments) no longer converts to jQuery(document).
  • .val(“…”) on an option or a checkbox is no longer ambiguous (it will always select by value now, not by text value). (Commit)
  • jQuery.browser.version now returns engine version.
  • We are now strict about incoming JSON and throw an exception if we get malformed JSON. If you need to be able to evaluate malformed JSON that is valid JavaScript, you can make a text request and use eval() to evaluate the contents.
  • Param serialization now happens in the PHP/Rails style by default. You can use jQuery.ajaxSettings.traditional = true; to use traditional parameter serialization. You can also set the behavior on a per-request basis by passing traditional: true to the jQuery.ajax method.
  • The internal jQuery.className removed.
  • jQuery.extend(true, …) No longer extends non-plain-objects or arrays.
  • If an Ajax request is made without specifying a dataType and it is returned as text/javascript, it will be executed. Previously, an explicit dataType was required.
  • Setting an Ajax request’s ifModified now takes ETags into consideration.

We’ve also written a plugin that provides backwards compatibility with every potentially-breaking change that we’ve made in 1.4. Feel free to download and include this plugin, after you’ve included 1.4, if you have any issues upgrading to 1.4.

How to use the plugin:

<script src="http://code.jquery.com/jquery.js"><!--mce:0--></script>
<script src="http://code.jquery.com/jquery.compat-1.3.js"><!--mce:1--></script>

Raw Data and Test Pages

For the performance tests we used the following test suites:

Raw data of the results (all numbers are 1.3.2 vs. 1.4):

# of function calls
547    3
760    3
500    200
896    399
23909    299
307    118
28955    100
28648    201
1662    593

DOM Insertion
558    317
1079    624
1079    516
1155    829
436    332
196    194
243    169

HTML
116    46
281    78
313    78
234    63
134    43
43    42
91    27

CSS/Attributes
703    370
1780    1250
1765    1250
1157    749
629    498
346    184
333    161

CSS
114    52
203    93
118    93
109    47
116    54
58    24
54    22

Classes
553    138
1578    546
1515    501
1033    327
769    298
229    80
173    41

Remove/Empty
3298    286
9030    2344
7921    1703
5282    1266
2898    303
1166    140
1034    122

jQuery 1.4 Live Q&A

Thanks for everyone who tuned in! Here is the full Q&A session in HD. A transcript is also being written.