JFast Javascript Library

JFast - High performance Javascript Library replace jQuery

1 . Why jFast?

Attribute
What it means

Tiny footprint

≈ 2 KB gzipped – ideal for embed widgets, dashboards, or legacy projects.

jQuery‑style API

80 % coverage of the helpers devs reach for most (addClass, on, ajax, …).

No build‑step

Ship the un‑minified file for debugging; run your own minifier if desired.

Polyfill friendly

Bundles fallbacks for Set and NodeList.forEach so IE11 gets basic support.

Modern under the hood

Uses querySelectorAll, classList, and Promises.


2 . Installation

<!-- 1. Download jfast‑1.2.3.js and place it in /assets/js -->
<script src="/assets/js/jfast-1.2.3.js"></script>

<!-- 2. Or, serve from your own CDN / S3 bucket -->
<script src="https://cdn.your‑domain.com/lib/jfast/1.2.3/jfast.min.js"></script>

When the script loads you’ll see a yellow console log:

jFast loaded version 1.2.3

and two globals become available:

console.log(window.jFast === window.$);   // true

3 . Creating a Collection

Below are all accepted constructor signatures, plus runnable snippets you can paste into DevTools.

Call
Typical Use Case
Example

jFast('section')

Select DOM by CSS

$('.box').addClass('open')

jFast(domNode)

Wrap an existing DOM node

jconst btn = document.getElementById('send');\n$(btn).attr('disabled', true);

jFast(NodeList)

Hand‑off result of querySelectorAll

const nodes = document.querySelectorAll('.note');\n$(nodes).hide();

jFast([el1,el2])

Wrap an array of nodes

$( [header, footer] ).css('background', '#333');

jFast(function)

DOM‑ready callback

$(function(){ console.log('DOM ready'); });

no value

Empty collection (edge cases)

jFast().length === 0;

Quick demo

<ul id="tasks">
  <li>Write docs</li>
  <li class="done">Ship release</li>
</ul>
<script>
  $('#tasks li:not(.done)')
    .addClass('pending')
    .each((i, li) => console.log('Todo #'+i, li.textContent));
</script>

4 . Core Iterator APIs

4.1 .each(callback)

Iterate the wrapped set. Unlike plain forEach, the callback is executed with (element, index) to match jQuery style.

$('a.external').each((i, a) => a.target = '_blank');

4.2 .eq(index)

Returns a new jFast collection containing just the element at index. Negative indices count from the end.

// Hide the last column in a table
$('table tr').find('td').eq(-1).hide();

4.3 .first() / .last()

Sugar for .eq(0) and .eq(length - 1).

$('.slide').last().addClass('current');

5 . Class Helpers

Method
Purpose
Minimal Demo

.addClass(names)

Add one or more classes

$('#msg').addClass('show animated');

.removeClass(names)

Remove class(es)

$('nav').removeClass('sticky');

.toggleClass(names, [state])

Flip class or force boolean state

$('.panel').toggleClass('open');

.hasClass(name)

Boolean test on first element

if ( $('#modal').hasClass('open') ) {...}

Practical scenario

// click to open/close FAQ answers
$('.faq-question').on('click', function () {
  $(this)
    .next('.faq-answer')
    .toggleClass('hidden');
});

6 . Attribute & Property Utilities

6.1 .attr(name) / .attr(name, value)

// Read
const src = $('img.preview').attr('src');

// Write
$('img.preview').attr('alt', 'Screenshot');

Remove an attribute:

$('input.temp').attr('autocomplete', null);

6.2 .prop(name[, value])

Directly modify DOM properties (not string attributes):

$('input[type=checkbox]').prop('checked', false);

6.3 .data(key[, value])

Free of JSON parsing/serialisation:

<div id="card" data-id="9810"></div>
<script>
  $('#card').data('id');       // "9810"
  $('#card').data('state', 'archived');
</script>

7 . Text, HTML, and Inline CSS

Getter
Setter
Sample

.text()

.text(value)

$('#status').text('Saving…');

.html()

.html(markup)

$('#list').html('<li>New item</li>');

.css(prop)

.css(prop, value)

$('#box').css('width', '250px');

.css(object)

$('#box').css({height:120, background:'#eef'});

8 . DOM Insertion & Removal

Method
What it does
Live Example

.append(content)

Add content to inside‑end of every element in the set.

$('#log').append('<li>Finished at '+Date.now()+'</li>');

.prepend(content)

Add content to inside‑start.

$('ul').prepend('<li class=\"first\">Top item</li>');

.before(content)

Insert content before each element.

$('.alert').before('<hr>');

.after(content)

Insert content after each element.

$('.alert').after('<button class=\"close\">×</button>');

.remove()

Detach each element from the DOM. Returns the same collection (now empty).

$('.toast .close').on('click', e => $(e.delegateTarget).parent('.toast').remove());

.empty()

Clear .innerHTML of every element but keep the elements themselves.

$('#results').empty(); // ready for fresh data

.clone([deep=true])

Produce a new jFast collection containing clones. deep=false copies only the element.

const $copy = $('#card').clone();\n$('#cards').append($copy);

Tip — Passing existing nodes All insertion helpers accept strings, HTMLElement(s), NodeLists, or jFast objects. If you pass DOM nodes, the library clones them when needed so every target gets its own copy.

$tmpl = $('#tmpl .item');      // template item stored off‑DOM
$('.list').append( $tmpl.clone() );  // safe – original remains intact

9 . Geometry & Scrolling Helpers

These methods read or write layout‑related values; none trigger a reflow more than necessary.

9.1 .width([value]) & .height([value])

Getter – returns the element’s content box size (ignores padding, border, margin). Setter – accepts number (pixels) or any valid CSS length string.

// Read
const modalW = $('#modal').width();          // e.g. 512

// Write absolute px
$('#sidebar').width(240);

// Write responsive unit
$('#sidebar').css('width', '33.333%');       // or use .css directly

9.2 innerWidth() / innerHeight()

Returns content + padding + border (matches jQuery.innerWidth). Useful for box‑model arithmetic:

if ( $box.innerHeight() < 200 ) $box.height(200);

9.3 outerWidth([includeMargin]) / outerHeight([includeMargin])

Adds margin when the optional boolean is true.

const cardTotal = $('.card').outerHeight(true);  // full footprint

9.4 .offset()

Absolute page coordinates (pixels from viewport’s top‑left, including scroll):

const pos = $('#avatar').offset(); // {top:123, left:456}
window.scrollTo({ top: pos.top - 20, behavior:'smooth' });

9.5 .position()

CSS position relative to offsetParent (similar to jQuery):

const { top, left } = $('#tooltip').position();
console.log('Tooltip is', top, 'px below its anchor');

9.6 .offsetParent()

Wraps and returns the element’s offset parent or document.documentElement.

$('#badge').offsetParent().css('outline','1px dashed red');

9.7 scrollTop([value]) / scrollLeft([value])

Works on both elements and window.

// Get current scroll
const y = $(window).scrollTop();

// Scroll container to bottom
$('#chat').scrollTop( $('#chat')[0].scrollHeight );

9.8 .index([element])

No argument → index of first element within its parent. Element argument → index of that element within the wrapped set.

const clickedCol = $(e.target).index();         // which column?
if ( clickedCol === 0 ) sortBy('name');

10 . Traversal Helpers

Method
Returned collection
Typical Use
Example

.find(sel)

All descendants matching sel.

Narrow to deeper nodes.

$('#nav').find('a.active')

.closest(sel)

First ancestor (self‑incl.) matching sel.

Bubble upward until match.

$(btn).closest('form').submit()

.parent()

The direct parent for every element.

Jump one level up.

$('.item').parent().addClass('has‑item')

.parents()

All ancestors for every element.

Apply global change along the chain.

$('#hero').parents().css('position','relative')

.children()

Direct child elements of each node.

Loop through immediate kids.

$('#menu').children().addClass('link')

.next() / .prev()

Immediate next/previous sibling.

Carousel, tab order, etc.

$('.tab.active').next().click()

.siblings()

All siblings except the element itself.

Row/column highlighting.

$(cell).siblings().addClass('dim')

.filter(sel)

Elements that pass selector test.

Refine a set post‑selection.

$('li').filter('.active, .current')

.not(sel)

Elements that fail selector test.

Exclude unwanted nodes.

$('li').not('.disabled')

.is(sel)

Bool – does the first element match?

Conditionals.

if ( $(el).is(':visible') ) …

.add(sel)

Union of current set + sel.

Merge disparate selections.

$('.btn').add('#save')


10.1 .find(selector)

Searches below every element in the current set.

<nav id="mainNav">
  <a href="/">Home</a>
  <a href="/shop" class="active">Shop</a>
</nav>
<script>
  $('#mainNav')
    .find('a.active')
    .css('font-weight',700); // only one link affected
</script>

Performance tipfind() re‑collects, so keep the result in a variable if you reuse it.


10.2 .closest(selector)

Works like native Element.closest. Includes the element itself when checking.

// inside a click handler on the document
$(e.target)
  .closest('[data-modal]')
  .addClass('open');

10.3 .parent() & .parents()

parent() climbs one level. parents() returns every ancestor up to <html>.

$('.note').parent().addClass('has-note');

$('.btn-save')
  .parents('section')        // only ancestors that are <section>
  .addClass('has-unsaved');

10.4 .children()

<ul id="files">
  <li>index.html</li>
  <li>app.js</li>
</ul>
<script>
  $('#files').children().each((i, li) => console.log(li.textContent));
</script>

10.5 .next() & .prev()

$('.wizard-step.active')
  .next()       // the step after the current one
  .addClass('active')
  .prev()       // go back to the previously active
  .removeClass('active');

10.6 .siblings()

$('.gallery img.selected')
  .siblings()
  .css('opacity',0.3);

10.7 .filter(), .not(), .is()

// Disable all but visible inputs
$('input').not(':visible').prop('disabled', true);

// Count only checked boxes
const checked = $('input[type=checkbox]').filter(':checked').length;

// Detect whether the page uses a dark theme
if ( $('body').is('.dark') ) enableNightMode();

10.8 .add(selector)

Merge two unrelated selections into one chainable set.

$('.toolbar button')
  .add('#globalSave')
  .on('click', saveDocument);

Mini Project Example – Building a Stepper

Below is a concise snippet that combines traversal helpers to implement a step‑by‑step UI.

<ol id="steps">
  <li class="step current">Choose plan</li>
  <li class="step">Billing info</li>
  <li class="step">Confirm</li>
</ol>
<button id="next">Next</button>

<script>
  $('#next').on('click', () => {
    const $current = $('#steps .current');
    $current.removeClass('current');
    $current.next('.step').addClass('current');
    
    // If we reached the end, disable the button
    if ( $('#steps .step').last().is('.current') ) {
      $('#next').prop('disabled', true);
    }
  });
</script>

Traversal calls used:

  • #steps .current – initial selection

  • .next('.step') – sibling traversal with selector filter

  • .last() / .is() – index check & boolean match

11 . Effects & Visibility Helpers

Method
Purpose
Default Duration
Example

.show([ms])

Make the element visible (removes display:none and optionally fades).

none

$('#loader').show(300)

.hide([ms])

Fade out then display:none.

none

$('.alert').hide(500)

.toggle([ms])

Switch between show ↔ hide.

none

$('#panel').toggle(200)

.fadeIn([ms])

Alias of .show() with default 400 ms when called without arg.

400 ms

$('img').fadeIn()

.fadeOut([ms])

Alias of .hide() with default 400 ms.

400 ms

$('img').fadeOut(150)

.slideDown([ms])

Animate height from 0 → full.

400 ms

$('.faq-answer').slideDown()

.slideUp([ms])

Animate height from full → 0, then display:none.

400 ms

$('.faq-answer').slideUp(250)

11.1 Show / Hide Example – Toast Notification

<div id="toast" class="toast">Saved!</div>
<style>
  .toast{position:fixed;bottom:1rem;right:1rem;padding:1em;background:#333;color:#fff;display:none}
</style>
<script>
  function flashToast() {
    $('#toast')
      .fadeIn(300)
      .delay(2000)            // custom helper below ▼
      .fadeOut(300);
  }

  // Tiny helper: chainable delay using setTimeout
  jFast.prototype.delay = function (ms) {
    return this.each(el => setTimeout(()=>{}, ms));
  };

  $('#saveBtn').on('click', flashToast);
</script>

11.2 Accordion with Slide Helpers

<h3 class="acc-title">Section 1</h3>
<div class="acc-body">Hidden text…</div>

<h3 class="acc-title">Section 2</h3>
<div class="acc-body">More hidden text…</div>

<script>
  $('.acc-title').on('click', function () {
    const $body = $(this).next('.acc-body');
    $('.acc-body').not($body).slideUp(); // close others
    $body.slideToggle();                 // jFast alias we can add
  });

  // Optional—extend jFast with slideToggle for convenience
  jFast.prototype.slideToggle = function (ms){
    return this.each(el => {
      const $el = $(el);
      $el.is(':visible') ? $el.slideUp(ms) : $el.slideDown(ms);
    });
  };
</script>

12 . Event System

jFast replicates jQuery’s flexible .on() signature, adds .one(), and keeps an internal WeakMap to clean listeners automatically.

12.1 .on(events, [selector], handler [, capture])

Pattern
Use‑case
Example

.on('click', fn)

Direct binding

$('#btn').on('click', save)

.on('keyup change', fn)

Multiple events space‑separated

$('input').on('keyup change', validate)

.on('click', '.child', fn)

Delegation (parent stays constant)

$('#list').on('click', 'li', editItem)

function editItem(e){
  // e.delegateTarget is the <li> that matched '.child'
  console.log('Editing', e.delegateTarget.textContent);
}

12.2 .one(events, [, selector], handler)

Runs once, then auto‑removes.

$('#modal').one('shown', () => console.log('Modal opened for the first time only'));

12.3 .off(events, [, selector], [handler])

Removes listeners. Parameters mirror .on(). Omitting handler drops all listeners matching event + selector.

$(window).off('scroll.myNS'); // if you namespaced your events

12.4 .trigger(type, [detail])

Dispatch custom or native events with optional detail payload.

// Somewhere deep in a component
$(this).trigger('saved', { id: 42 });

// Elsewhere
$(document).on('saved', (e)=> console.log('Item saved!', e.detail.id));

Note: Native bubbling rules apply, so you can trigger on a child and listen on <body>.

12.5 Event Shortcut Methods

For convenience jFast defines typed aliases:

$('#field').focus();           // trigger focus
$('#field').focus(handler);    // bind

$('form').submit(e => e.preventDefault());
$(document).keydown(e => e.key === 'Escape' && close());

Available shortcuts: click, change, keydown, keyup, keypress, mouseover, mouseout, mouseenter, mouseleave.


12.6 Real‑World: Live Search with Debounce

<input id="search" placeholder="Search…" autocomplete="off">
<ul id="results"></ul>

<script>
  // --- simple debounce utility
  function debounce(fn, wait){
    let t; return (...args)=>{ clearTimeout(t); t=setTimeout(()=>fn.apply(this,args), wait); };
  }

  $('#search').on('keyup', debounce(function(){
    const q = $(this).val().trim();
    if (!q) return $('#results').empty();

    $.getJSON('/api/search', {q})
      .success(data => {
        const html = data.results.map(r => `<li>${r.title}</li>`).join('');
        $('#results').html(html);
      });
  }, 300));
</script>

Techniques used

  • Direct event binding (keyup)

  • Reading input value with .val()

  • Ajax shorthand $.getJSON

  • DOM diff via .html(html)


Recap

Effects handled: show/hide, fade, slide, toggle. Events mastered: .on, .one, .off, .trigger, plus typed shortcuts & delegation patterns.

13 . Form Helpers

API
Read / Write
Quick Example

.val() / .val(value)

Get or set an element’s value. Works on <input>, <select>, <textarea>, check‑/radio boxes (boolean support), and multi‑select arrays.

$('#email').val('[email protected]');

.serialize()

Return URL‑encoded query string from the first <form> in the set.

$('form').serialize(); // "name=Bob&age=28"

.serializeArray()

Return array [{name:'', value:''}, …].

console.table($('form').serializeArray());

.submit()

Programmatically send a form (respects requestSubmit when present). Passing a submit button as the jFast object triggers that button.

$('#myForm').submit();

13.1 .val() in Depth

<select id="lang" multiple>
  <option value="en" selected>English</option>
  <option value="vi" selected>Vietnamese</option>
  <option value="jp">Japanese</option>
</select>

<script>
  // Get → returns array for multi‑select
  const langs = $('#lang').val();      // ["en","vi"]

  // Set (array) → selects those options
  $('#lang').val(['jp']);
</script>

Checkbox toggle:

// set boolean
$('#notify').val(true);          // checks it
$('#notify').val(false);         // unchecks

13.2 AJAX Submit with .serialize()

<form id="login">
  <input name="user" placeholder="Username">
  <input name="pass" type="password">
  <button type="submit">Login</button>
</form>

<script>
  $('#login').on('submit', e => {
    e.preventDefault();                     // stop native redirect
    const qs = $(e.currentTarget).serialize();
    $.post('/api/login', qs)
      .success(res  => console.log('OK', res))
      .fail   (err  => alert('Bad credentials'));
  });
</script>

14 . Ajax in Depth — Working With Remote Data

jFast’s Ajax layer shadows jQuery’s API line‑for‑line yet trims weight by delegating to the native XMLHttpRequest. You may call it at three levels of abstraction:

  1. Low‑level $.ajax( settings ) – full control.

  2. Semantic helpers $.get / $.post / $.getJSON – 90 % of daily tasks.

  3. Chainable XHR “deferred” object – classic jQuery style (done / fail / always) plus promise (then / catch / finally).

Below is a complete reference with production‑grade snippets.


14.1 $.ajax( settings ) — Master Control

14.1.1 Settings Object Cheat‑Sheet

Key
Type / Default
Description

url

string / required

Endpoint.

type

"GET"

HTTP verb ("POST", "PUT", …).

data

object | string | FormData

Will be encoded automatically unless FormData.

dataType

"json" | "html" | "script"

Guides auto‑parsing & Accept header (falls back to */*).

contentType

application/x-www-form-urlencoded; charset=UTF-8

false = let the browser pick (required for FormData).

async

true

Set false only for legacy sync calls (blocks UI).

headers

object

Extra request headers.

username, password

string

For HTTP basic auth.

Callbacks

beforeSend, success, error, complete

Same signatures as jQuery.

Encoding Rules

  • If data is plain object → encoded via $.param() unless contentType starts with application/json.

  • If type is GET/HEAD/DELETE and data is not null → appended to the URL query string.

  • If data is FormData → jFast will not set Content‑Type so the boundary is correct.

14.1.2 Full Example – PUT JSON With Auth Header

const profile = { bio: 'Hello there', age: 30 };

$.ajax({
  url: '/api/v1/users/42',
  type: 'PUT',
  data: JSON.stringify(profile),
  contentType: 'application/json',
  dataType: 'json',
  headers: { 'Authorization': 'Bearer ' + token },
  beforeSend(xhr) { console.log('Uploading…'); },
  success(data, status, xhr) { console.log('Saved!', data); },
  error(xhr, status, text) { console.error('Server said:', text); },
  complete(xhr, status) { console.log('Request finished:', status); }
});

14.1.3 Promise Interface (& Abort)

const req = $.ajax('/search?q=cat')
  .then(res  => render(res.items))
  .catch(e   => alert('Network problem: ' + e.status))
  .finally(() => spinner.hide());

// Abort button
$('#cancel').on('click', () => req.abort && req.abort());

The returned XHR object is augmented with both promise methods and jQuery‑style done / fail / always.

14.1.4 Monitoring Upload / Download Progress

$.ajax({
  url: '/upload',
  type: 'POST',
  data: new FormData($('#fileForm')[0]),
  contentType: false,
  beforeSend(xhr){
    xhr.upload.onprogress = e => {
      if (e.lengthComputable){
        const pct = (e.loaded / e.total * 100) | 0;
        $('#bar').css('width', pct+'%');
      }
    };
  }
});

14.2 Helper Shortcuts

Helpers internally call $.ajax but save keystrokes. All optional arguments may be omitted in order; jFast adjusts.

Helper
Signature (flexible)
Internals

$.get(url [, data] [, success] [, dataType])

Always GET.

$.ajax({type:'GET', …})

$.post(url [, data] [, success] [, dataType])

Always POST.

$.ajax({type:'POST', …})

$.getJSON(url [, data] [, success])

Forces dataType:'json'.

$.get(… , 'json')

14.2.1 GET With Query Object

$.get('/api/products', { page: 2, tag: 'book' }, buildGrid, 'html');

14.2.2 POST Form (x‑www‑form‑urlencoded)

$.post('/login', { user, pass })
  .done(()  => location.reload())
  .fail(()  => shakeForm());

14.2.3 GET JSON via $.getJSON

$.getJSON('/weather', { city: 'Singapore' })
  .then(({ temp, icon }) => $('#temp').text(temp + '°C')
                                      .attr('class', icon));

14.3 Using FormData for File Uploads

<form id="avatarForm">
  <input type="file" name="avatar">
  <button>Upload</button>
</form>

<script>
$('#avatarForm').on('submit', e => {
  e.preventDefault();
  const formData = new FormData(e.currentTarget);

  $.ajax({
    url: '/api/upload/avatar',
    type: 'POST',
    data: formData,
    contentType: false,   // *DO NOT OVERRIDE* for FormData
    processData: false,   // jFast handles this automatically
    dataType: 'json'
  })
  .success(data => alert('URL: ' + data.url))
  .error  (()  => alert('Upload failed'));
});
</script>

14.4 Error‑Handling Patterns

Scenario
Strategy

Validation errors (422)

In error callback, check xhr.status === 422 then read JSON.parse(xhr.responseText) to show field‑level messages.

Timeout / offline

Use xhr.status === 0 or wrap the promise in a Promise.race([ajax, timeout]).

Retry

Write a helper: function withRetry(fn, n){ return fn().catch(e => n>0 ? withRetry(fn, n‑1) : Promise.reject(e)); }.


14.5 Quick Reference

$.ajax(settings)    // full power
$.get(url[,data][,success][,type])
$.post(url[,data][,success][,type])
$.getJSON(url[,data][,success])

XHR methods: then, catch, finally, done, fail, always, success, error, complete, abort

With this toolkit you can cover everything from vanilla REST endpoints to streaming uploads in a few lines of code.

15 . Why Static Utilities?

Everything in this chapter is independent of a wrapped DOM collection; you can feed plain arrays, NodeLists, or objects. jFast purposely mirrors jQuery naming so muscle memory applies.


15.1 jFast.each( collection, callback )

Iterates any array‑like structure.

const colors = ['teal', 'pink', 'orange'];

$.each(colors, (idx, val) => console.log(idx, val.toUpperCase()));
// 0 TEAL · 1 PINK · 2 ORANGE

Characteristics:

  • Works on NodeList directly (no spread required).

  • Callback signature is (index, item) like jQuery (not (item,index)).


15.2 jFast.map( collection, callback )

Transforms each item; returns new array.

const lens = $.map(document.querySelectorAll('p'), p => p.textContent.length);
console.log(lens); // e.g. [25, 18, 42]

If the callback returns null or undefined, the item is skipped (parity with jQuery).


15.3 jFast.grep( array, predicate )

Filters items; returns new array.

const nums   = [5, 8, 9, 13, 21, 22];
const primes = $.grep(nums, n => [2,3,5,7,11,13,17,19,23].includes(n));

Tip – Because grep creates a new array, it’s ideal for immutable Redux‑style flows.


15.4 jFast.inArray( item, array )

Returns index (>=0) or -1.

if ($.inArray('admin', user.roles) === -1) denyAccess();

15.5 jFast.param( object [, prefix] )

Serialises nested objects the PHP / Rails‑style way.

const criteria = {
  sort:  'date',
  range: { from: '2025-01-01', to: '2025-06-30' },
  tags:  ['node', 'api']
};

const qs = $.param(criteria);
console.log(qs);
// "sort=date&range[from]=2025-01-01&range[to]=2025-06-30&tags[0]=node&tags[1]=api"

fetch('/search?' + qs).then(r => r.json());

15.6 jFast.extend( target, …sources ) — Deep Merge Engine

Unlike a shallow Object.assign, jFast’s extend recurses into nested objects but leaves arrays intact.

const defaults = {
  ui:   { theme: 'light', density: 'comfortable' },
  rate: 1000
};
const userCfg  = { ui: { density: 'compact' } };

const finalCfg = $.extend({}, defaults, userCfg);
/* finalCfg === {
     ui:   { theme: 'light', density: 'compact' },
     rate: 1000
   } */

15.6.1 Adding Prototype Plugins

Because extend is exported, you can patch either the global jFast or its prototype.

// Static helper
$.extend($, {
  random(min, max){ return Math.floor(Math.random()*(max-min+1))+min; }
});

// Chainable instance helper
$.extend($.prototype, {
  flash(ms = 150){
    return this.each(el => {
      const orig = el.style.transition;
      el.style.transition = 'background ' + ms + 'ms';
      el.style.background = '#ffe66d';
      setTimeout(() => { el.style.background=''; el.style.transition=orig; }, ms);
    });
  }
});

// Usage
console.log($.random(1,6)); // dice roll
$('.btn-save').flash();

15.7 Utility Comparison Table

Use‑case
Vanilla ES
jFast Utility
Snippet

Iterate NodeList

Array.from(nodes).forEach

$.each(nodes, fn)

$.each(document.links, cb)

Map values

[...arr].map

$.map(arr, fn)

$.map($('li'), li => li.id)

Deep‑merge configs

structuredClone + custom

$.extend

$.extend({}, def, opt)

Encode query string

URLSearchParams

$.param (handles nested)

$.param({page:2})


What’s Next?

With Static Utilities mastered you have:

  • Collection‑agnostic helpers (each, map, grep).

  • Query‑string encoding & deep merges.

  • A building block (extend) for your own plugins.

16 . Authoring Plug‑ins

jFast keeps the exact extension workflow you know from jQuery: augment either jFast.prototype (for chainables) or jFast itself (for statics). Everything hinges on jFast.extend.

16.1 Guidelines

Rule
Rationale

Return this to stay chainable.

Keeps plug‑in composable with core helpers.

Store per‑element state in el.dataset or a WeakMap.

Avoids leaking memory when nodes are removed.

Use a unique data‑key namespace (e.g. "popover-active").

Prevents collisions between plug‑ins.

Accept an options object & merge with defaults via jFast.extend.

Enables declarative config + sane fall‑backs.

16.2 Micro‑Plug‑in Example — highlight()

(function ($) {
  const defaults = { color: '#fffd54', duration: 600 };

  $.extend($.prototype, {
    highlight(opts){
      opts = $.extend({}, defaults, opts);
      return this.each(el => {
        const orig   = getComputedStyle(el).backgroundColor;
        el.style.transition = `background ${opts.duration}ms`;
        el.style.background = opts.color;
        setTimeout(() => el.style.background = orig, opts.duration);
      });
    }
  });
})(jFast);

// usage
$('table tr.error').highlight({ color:'#ff8080' });

16.3 Feature‑Rich Plug‑in Template (Modal)

/* modal.js – UMD style */
(function (root, factory) {
  if (typeof define === 'function' && define.amd) define(['jFast'], factory);
  else factory(root.jFast);
}(this, function ($) {

  const DATA_KEY = 'modalInstance';
  const defaults = { closeBtn: true, esc: true, backdrop: true };

  class Modal {
    constructor(el, opts){
      this.$el  = $(el);
      this.opts = $.extend({}, defaults, opts);
      this.bind();
    }
    bind(){
      if (this.opts.closeBtn){
        this.$el.find('[data-dismiss="modal"]').on('click', ()=> this.hide());
      }
      if (this.opts.esc){
        $(document).on('keydown.modal', e => e.key==='Escape' && this.hide());
      }
    }
    show(){
      this.$el.fadeIn(200).attr('aria-hidden', false);
      $(document.body).addClass('modal-open');
    }
    hide(){
      this.$el.fadeOut(150).attr('aria-hidden', true);
      $(document.body).removeClass('modal-open');
    }
    toggle(){ this.$el.is(':visible') ? this.hide() : this.show(); }
  }

  /* jFast bridge */
  $.extend($.prototype, {
    modal(cmdOrOpts){
      return this.each(el => {
        let inst = $(el).data(DATA_KEY);
        if (!inst){
          inst = new Modal(el, typeof cmdOrOpts==='object' ? cmdOrOpts : {});
          $(el).data(DATA_KEY, inst);
        }
        if (typeof cmdOrOpts === 'string'){
          inst[cmdOrOpts] && inst[cmdOrOpts]();
        }
      });
    }
  });
}));

Usage:

$('#myModal').modal({ backdrop:false });
$('#launch').on('click', () => $('#myModal').modal('show'));

16.4 Testing jFast Plug‑ins with Jest + jsdom

  1. Install Dev Deps

npm i --save-dev jest @jest-environment-jsdom
  1. Setup Global $ in jest.setup.js

require('../dist/jfast');           // expose global jFast
global.$ = global.jFast;
// jest.config.json
{
  "setupFiles": ["<rootDir>/test/jest.setup.js"],
  "testEnvironment": "jsdom"
}
  1. Write a Spec

describe('highlight plug‑in', () => {
  document.body.innerHTML = '<p id="a">text</p>';
  
  test('changes background then reverts', done => {
    const $p = $('#a');
    $p.highlight({ color:'#abc', duration:50 });

    expect($p.css('background')).toBe('rgb(170, 187, 204)');
    
    setTimeout(() => {
      expect($p.css('background')).toBe('');
      done();
    }, 60);
  });
});
  1. Run

npx jest

jsdom simulates enough of CSSOM for simple animation assertions; for layout you might stub getBoundingClientRect.


16.5 Performance Best‑Practices

Topic
Recommendation
Why

Batch DOM writes

Build HTML strings or DocumentFragment, then .append() once.

Cuts reflow counts.

Delegate events

Attach one on('click', selector, …) at container level instead of many direct listeners.

Lower memory & faster diff when nodes mutate.

Avoid synchronous Ajax

async:false blocks the UI; keep default true.

Network stalls freeze the main thread.

Measure

Drop console.time() around chains or use Chrome DevTools Performance tab.

Data > guesswork.

Destroy observers

If a plug‑in uses ResizeObserver or MutationObserver, disconnect in remove() or hide().

Prevents leaks on SPA route change.

Minify for production

jFast is readable by design—pass through Terser to shave ~35 %.

Smaller payload → TTI gains.

Tree‑shake unused plug‑ins

Author plug‑ins as separate files so bundlers can exclude them.

Keeps your vendor chunk tiny.

Example – Batch Update vs. O(n) Loop

// baseline: O(n) reflow
$('li').each((i, el) => $(el).addClass('done'));

// optimized: CSS class on the parent
$('#todo').addClass('all-done');

16.6 Performance Snippet: Virtualized List (100 k rows)

function mountVirtual($container, rows){
  const rowH = 30, buffer = 10;
  $container.height(rows.length * rowH);     // big scroll area

  const $viewport = $('<div class="viewport"></div>').appendTo($container.parent());

  function render(){
    const top = $container.parent().scrollTop();
    const start = Math.max(0, Math.floor(top / rowH) - buffer);
    const end   = Math.min(rows.length, start + Math.ceil($viewport.height()/rowH) + buffer*2);
    const slice = rows.slice(start, end)
                      .map((txt,i)=> `<div class="row" style="top:${(start+i)*rowH}px">${txt}</div>`)
                      .join('');
    $container.html(slice);
  }
  $container.parent().on('scroll', render);
  render();
}

Demonstrates:

  • Single delegated scroll handler.

  • position:absolute rows avoid layout for hidden items.

  • html(slice) rewrites once per frame.

A. Frequently Asked Questions (FAQ)

Question
Short Answer

Does jFast support IE 11?

Partially. Core DOM helpers work thanks to built‑in polyfills (Set, NodeList.forEach). You still need a Promise polyfill for Ajax.

Can I load jFast alongside jQuery?

Yes. jFast attaches both jFast and $. If jQuery is present first, jFast will not overwrite $; access it via window.jFast.

How big is the minified build?

Un‑minified: 9.6 KB. Minified + gzip: ≈ 2 KB.

Is there ES Module support?

Planned for v1.3.0. For now you can import the UMD file in bundlers (Rollup / Webpack) without issues.

How do I remove the global $?

Wrap the script in a closure: ;(function(priv){ /* docs here */ })(jFast); and avoid referring to $ globally.

What about TypeScript types?

A community‑maintained @types/jfast will debut after v1.3.0. Until then, declare const $: typeof jFast; in a d.ts.


B. Migrating From jQuery 3.x to jFast 1.x

jQuery Code
jFast Equivalent
Notes

$(dom).fadeToggle(150)

$(dom).toggle(150)

jFast combines fade into toggle.

$.ajaxSetup({...})

(none)

jFast aims for statelessness; pass settings per‑request.

$('form').serializeArray()

Same

Fully supported.

$(img).on('load', fn)

Same

Event helpers identical.

$(el).css({ top:0 }).animate({ top:200 })

Use CSS transitions or slideDown/Up

jFast provides only basic slide/fade; no full animate.

$.Deferred()

Use native Promise or $.ajax() returned promise

Promise polyfill required on old browsers.

Cheat Migration Recipe

  1. Replace jQuery script tag with jFast.

  2. Scan for non‑supported APIs: .animate, ajaxSetup, $.proxy, $.fn.extend (replace with jFast.extend).

  3. Polyfill Promise if targeting ES5 browsers.

  4. Test on evergreen browsers; then add polyfills as necessary.


C. Roadmap (2025 ↦ 2026)

Milestone
ETA
Highlights

v1.3.0

Q3 2025

Native ES Module bundle, built‑in Promise polyfill toggle, new helper .toggleAttr

v1.4.0

Q1 2026

Animation engine (CSS keyframe wrapper), $.ajaxSetup, fetch‑based Ajax fallback

v2.0.0

TBD

Drops IE 11 support, swaps internal XHR for fetch, tree‑shake‑friendly build targets.

Community feedback on GitHub issues tagged proposal-* steers prioritisation.


D. Additional Resources

  • Issues / Discussions – good first issues labelled “help wanted”

  • CDN – CDN link generator: https://cdn.jsdelivr.net/npm/[email protected]/dist/jfast.min.js

  • Starter Plug‑insmodal.js, tooltip.js, virtualList.js in /plugins directory

  • Unit Test Suite – sample Jest configuration in /test folder


E. Final Thoughts

jFast was built for developers who love jQuery’s ergonomics but need a fraction‑of‑the‑weight helper in 2025‑era projects. Its small, readable source aims to be a living tutorial—feel free to fork, audit, and tailor it to your own design system.

Thank you for reading through all parts. If you find a bug, open an issue or submit a pull‑request—every line counts!

— CMS Full Form, Maintainer

Last updated

Was this helpful?