jQuery · Practice

jQuery Best Practices

jQuery code ages well when it follows a few habits. These practices keep pages fast, code readable and future migrations to plain JavaScript easy.

Advanced 5 min Lesson 20 of 22 Runnable examplesExamples use jQuery 3.x.
Before you start:Event DelegationPlugins
0/22 in jQuery
On this page · 5 min · Advanced

Learning objectives#

  • Write fast selections and DOM updates
  • Organise code into modules without globals
  • Handle events and AJAX robustly
  • Decide between jQuery and native APIs

Explanation#

Cache and scope: const $list = $("#list"); then $list.find(".item") — fewer DOM searches, clearer code.

Batch DOM work: build elements (or an array of them) and append once, instead of appending inside a loop.

Delegate events from stable containers, and namespace them (click.cart) so you can remove only your own.

Avoid globals: wrap page code in a module (an IIFE or ES module) and expose one small object if needed.

Security: .text() for user data, anti-forgery tokens on POST, never eval server responses.

Know the native equivalents (querySelectorAll, classList, fetch, addEventListener). In new code, a few lines of plain JavaScript usually beat adding a 30 KB library.

Code example: Before and after: the same feature, done well#

HTMLBefore and after: the same feature, done well Runnable
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<div id="app" style="font-family:sans-serif"><button class="load">Load products</button><ul class="list"></ul></div>
<script>
  // ✓ One module, no globals, cached and scoped selections, batched DOM updates
  const ProductList = (function ($) {
    const products = [{ name: 'Pen', price: 20 }, { name: 'Notebook', price: 60 }, { name: '<script>alert(1)<\/script>', price: 1 }];


    function render($root) {
      const $items = products.map(p => $('<li>').text(p.name + ' — ₹' + p.price));   // .text() = safe
      $root.find('.list').empty().append($items);                                      // one DOM update
    }


    function init(selector) {
      const $root = $(selector);                                                       // cached
      $root.off('.products').on('click.products', '.load', () => {                    // namespaced + delegated
        render($root);
        console.log('Rendered', $root.find('.list li').length, 'items');
      });
    }


    return { init };
  })(jQuery);


  $(function () { ProductList.init('#app'); });
</script>
Expected output
Clicking “Load products” renders three items in one DOM update and logs “Rendered 3 items”. The third product’s name containing a script tag is shown as plain text, not executed. No global variables except ProductList are created.
Opens this example in the full playground

Step-by-step explanation#

  1. The IIFE keeps products and helpers private; only ProductList.init is public.
  2. $root is selected once and all other lookups are scoped to it.
  3. All list items are built in an array and appended in a single call.
  4. The click handler is namespaced (.products) and delegated, so init can be called again safely.
  5. .text() neutralises the malicious product name.

Real-world use case#

A team modernising a legacy site first refactors its jQuery into modules following these rules. Later, swapping jQuery calls for native ones module by module becomes straightforward.

Common mistakes#

Re-selecting in loops

$(".total") inside a loop of 1,000 rows searches the DOM 1,000 times. Select once outside.

Huge $(document).ready blocks

Hundreds of lines in one ready callback become unmaintainable. Split into named modules and functions.

Adding jQuery to new projects for small tasks

Native APIs now cover selection, classes, events and fetch. Add jQuery only when you need its plugins or are in a jQuery codebase.

Best practices#

  • Cache and scope selections
  • Append once per batch
  • Delegate and namespace events
  • Modules instead of globals; .text() for user data

Remember this#

Select once, reuse $variables.

Build, then append once.

New project? Try native JS first.

Practice exercise#

Your task: Refactor: for (let i = 0; i < 100; i++) { $("#list").append("<li>" + i + "</li>"); } so it touches the DOM only once.

Need a hint?
Build an array of $("<li>") elements, then $("#list").append(array).
Show solution
HTML Runnable
<script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
<ul id="list"></ul>
<script>
  $(function () {
    const items = [];
    for (let i = 0; i < 100; i++) items.push($('<li>').text(i));
    $('#list').append(items);
    console.log($('#list li').length);   // 100
  });
</script>
Opens this example in the full playground

Mini quiz#

jQuery Best Practices quizMultiple choice Question 1 of 3

Which is faster for adding 500 rows?

Score so far: 0/0

Want more? Practise all jQuery MCQs · jQuery interview questions

My notes#

Saved in this browser.

Progress is saved in this browser. Sign in to sync.