Last updated August 12, 2013. Created by gagarine on August 9, 2012.
Edited by Cottser, Mark Carver, oresh, Wim Leers. Log in to edit this page.

Prefix variables that point to jQuery objects with a dollar sign($)

In any part of your code it should be easy to understand which variables are jQuery objects and which are not.

Incorrect

var foo = $('.foo');
var object = { bar: $('.bar') };

Correct
var $foo = $('.foo');
var object = { $bar: $('.bar') };

Avoid compatibility issues

jQuery is evolving quickly but attempts to maintain backward compatibility with previous releases. Although multiple jQuery versions are not officially supported within a single Drupal major release, many sites use the jQuery update module to take advantage of performance and bug fixes offered by newer versions of jQuery. Custom modules using jQuery should keep up to date with syntax best-practices in order to avoid conflicts with updated versions.

Chaining

For chaining selector you can either use CSS method $(' a b > c') or JavaScript chaining $('a').find('b').children('c'). Second method is slightly faster(test). In both cases reduce the weight of selector(if possible). In case .children() and .find() will return the same results, use .find() method (test).
Incorrect

   this.$el
       .find('.contextual-links')
       .prop('hidden', !isOpen);

Correct
    this.$el.find('.contextual-links')
      .prop('hidden', !isOpen);

Event Delegation

Every event (e.g. click, mouseover, etc.) in JavaScript “bubbles” up the DOM tree to parent elements. This is incredibly useful when you want many elements to call the same function. Instead of binding an event listener function to all of them, you can bind it once to their parent, and have it figure out which node triggered the event.

In examples of jQuery code, you may often see events simply return false; to prevent the default behavior of that event. This type of prevention is often misused and also prevents the "bubbling" propagation of the event. This effect is not always desired. If you wish to either prevent the default behavior or stop propagation, they should be explicitly defined.

Incorrect

$('.item').click(function(event) {
  ...
  // Calls both event.preventDefault() and event.stopPropagation().
  return false;
});

Correct (Drupal 7)
$menus.delegate('.item', 'click', function(event) {
  ...
  // Prevents the default behavior (ie: click).
  event.preventDefault();
  // Prevents propagation (ie: "bubbling").
  event.stopPropagation();
});

Correct (Drupal 8)
$menus.on('click', '.item', function(event) {
  ...
  // Prevents the default event behavior (ie: click).
  event.preventDefault();
  // Prevents the event from propagating (ie: "bubbling").
  event.stopPropagation();
});

Functions

Separate your functions into individual functions and call them when needed.
Incorrect

// Can be called only on click.
$('.btn').click( function() { ... });

Correct
// Can be called anywhere.
function clickFunction() { ... };
$('div').click( function() {clickFunction() });

Context

Always try to give your selectors a context. The default context will search the entire page's DOM. If the context is a cached selection, use find().
Incorrect

// This has no context and is very slow.
var $element = $('.element');

Improved
// Search only in #sidebar.
var $element = $('.element', '#sidebar');

Correct
var $sidebar = $('#sidebar');
var $element = $sidebar.find('.element');

Using #id or .class

Finding elements by the tag ID is much faster (test) then by class name. If your target element appears on the page only once, select it by #id. In case when you have more than one, use class but descend from an #id. See the above context code examples.

jQuery.attr()

This applies only for D6 and D7 because D8 will ship with jQuery 1.9+ which instead uses .prop() for property.
Wrong use of .attr is the cause of the many compatibility problems. Use booleans to set a property, not an empty string. Also, do not assume that property values that are returned are always booleans. .attr('checked') could return either true or 'checked' depending on jQuery version and markup.
Incorrect

$element.attr('disabled', '');
if ($element.attr('checked') === true) { ... }

Correct
$element.attr('disabled', false);
$element.attr('disabled', true);
if ($element.attr('checked')) { ... }

jQuery.each()

This method is indeed very powerful (and appropriate) when dealing with existing instantiated jQuery objects and the need to iterate on them.

It is often misused when needing to iterate over simple native JavaScript arrays or objects. Using native JavaScript for loops are 300-1000 times faster than jQuery.each() (test).
Incorrect

var array = [ ... ];
$.each(array, function(i, item) { ... });

Correct
var array = [ ... ];
for(var i, len = array.length; i < len; i += 1){
  var element = array[i];
}

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.