Functions on $ itself
Most of jQuery works on selections: $("p").hide(). A smaller set of utility functions live directly on $ and work on ordinary values: objects, arrays and strings. You met $.each() and $.escapeSelector() earlier. This lesson covers the rest that you are likely to meet.
Merging objects with $.extend()
$.extend(target, obj1, obj2, ...) copies the properties of each object into target, from left to right, and returns target. Later objects win:
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
const defaults = { speed: 300, colour: "yellow", closeButton: true };
const options = { colour: "pink" };
const settings = $.extend({}, defaults, options);
console.log("settings:", JSON.stringify(settings));
console.log("defaults unchanged:", JSON.stringify(defaults));
</script>settings: {"speed":300,"colour":"pink","closeButton":true}
defaults unchanged: {"speed":300,"colour":"yellow","closeButton":true}Passing an empty object as the target is the important part: it makes a new object and leaves defaults and options untouched. This "defaults plus options" pattern is how almost every jQuery plugin handles settings (next lesson). Modern JavaScript can do the same with { ...defaults, ...options }.
Shallow versus deep
By default, $.extend is shallow: a nested object in a later argument replaces the earlier one completely. Pass true as the first argument for a deep merge:
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
const defaults = { text: { open: "Open", close: "Close" }, speed: 300 };
const options = { text: { open: "Show" } };
console.log("shallow:", JSON.stringify($.extend({}, defaults, options)));
console.log("deep: ", JSON.stringify($.extend(true, {}, defaults, options)));
</script>shallow: {"text":{"open":"Show"},"speed":300}
deep: {"text":{"open":"Show","close":"Close"},"speed":300}The shallow merge lost close, because the whole text object was replaced. The deep merge kept it. $.extend(true, {}, obj) is also a quick way to make a deep copy of plain data.
Looping, transforming and filtering
These three work on arrays and, for $.each and $.map, on objects too:
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
const prices = { lamp: 1200, pen: 40, desk: 8500, mug: 250 };
$.each(prices, (name, price) => { if (price > 1000) console.log("each:", name, "is over 1000"); });
const labels = $.map(prices, (price, name) => name + " (" + price + ")");
console.log("map:", labels.join(", "));
const cheap = $.grep(Object.values(prices), price => price < 500);
console.log("grep:", cheap);
console.log("grep inverted:", $.grep([1, 5, 8, 12], n => n > 6, true));
</script>each: lamp is over 1000
each: desk is over 1000
map: lamp (1200), pen (40), desk (8500), mug (250)
grep: [40, 250]
grep inverted: [1, 5]$.each(collection, fn)loops; for arrays the arguments are(index, value), for objects(key, value). Returnfalseto stop.$.map(collection, fn)builds a new array from the return values. Returningnullorundefinedskips an item, and returning an array adds all its items (it flattens one level). Note the argument order is(value, key), the opposite of$.each.$.grep(array, fn, invert)keeps items for whichfnreturns true, likeArray.prototype.filter. Passtrueas the third argument to keep the others instead.
For plain arrays, modern JavaScript's forEach, map and filter do the same and are more common in new code.
Testing values
<div id="outer"><span id="inner"></span></div>
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
console.log("isPlainObject({}):", $.isPlainObject({}));
console.log("isPlainObject([]):", $.isPlainObject([]));
console.log("isPlainObject(new Date()):", $.isPlainObject(new Date()));
console.log("isEmptyObject({}):", $.isEmptyObject({}));
console.log("isEmptyObject({ a: 1 }):", $.isEmptyObject({ a: 1 }));
console.log("contains(outer, inner):", $.contains($("#outer")[0], $("#inner")[0]));
console.log("inArray('pen', list):", $.inArray("pen", ["lamp", "pen", "mug"]));
</script>isPlainObject({}): true
isPlainObject([]): false
isPlainObject(new Date()): false
isEmptyObject({}): true
isEmptyObject({ a: 1 }): false
contains(outer, inner): true
inArray('pen', list): 1$.isPlainObject(value): is it a simple{ }object, not an array, date or DOM element? Useful for telling an options object from other arguments.$.isEmptyObject(obj): does it have no properties?$.contains(parent, child): is the DOM elementchildinsideparent? (Both must be plain elements.)$.inArray(value, array): the index, or-1; the same asarray.indexOf(value).
Building query strings
$.param(object) turns an object into a URL query string, the format Ajax GET requests and form posts use:
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
console.log($.param({ q: "desk lamp", page: 2, tags: ["oak", "led"] }));
console.log(new URLSearchParams({ q: "desk lamp", page: 2 }).toString());
</script>q=desk%20lamp&page=2&tags%5B%5D=oak&tags%5B%5D=led
q=desk+lamp&page=2Arrays become tags[]=oak&tags[]=led (encoded), which PHP and many frameworks read as an array. The built-in URLSearchParams is a modern alternative; notice that it encodes spaces as + rather than %20, and handles arrays differently.
Removed in jQuery 4
jQuery 4 removed several utilities that duplicated built-in JavaScript. You will still see them in older code, and the upgrade lesson shows how to find them:
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
const removed = ["trim", "isArray", "isFunction", "isNumeric", "type", "parseJSON", "now", "unique", "isWindow", "camelCase", "nodeName"];
console.log("still present:", removed.filter(name => typeof $[name] === "function").join(", ") || "none");
</script>still present: none| Old jQuery | Use instead |
|---|---|
$.trim(text) |
text.trim() |
$.isArray(value) |
Array.isArray(value) |
$.isFunction(value) |
typeof value === "function" |
$.isNumeric(value) |
Number.isFinite(Number(value)) (check how you want to treat empty strings) |
$.type(value) |
typeof, Array.isArray, instanceof |
$.parseJSON(text) |
JSON.parse(text) |
$.now() |
Date.now() |
$.unique(elements) |
$.uniqueSort(elements) |
$.proxy(fn, context) is deprecated but still present; the modern form is fn.bind(context) or an arrow function.
Common mistakes
$.extend(defaults, options)without an empty target, which changes your defaults for every later use.- Expecting a shallow
$.extendto merge nested objects. - Mixing up argument orders between
$.each(index, value) and$.map(value, index). - Calling removed helpers such as
$.trimafter upgrading to jQuery 4.
Exercise
Write a function makeSettings(options) that merges options into the defaults { theme: "light", layout: { columns: 2, gap: 8 } } with a deep merge, without changing the defaults. Log the result of makeSettings({ layout: { columns: 3 } }).
Show one possible answer
<script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
<script>
const DEFAULTS = { theme: "light", layout: { columns: 2, gap: 8 } };
function makeSettings(options) {
return $.extend(true, {}, DEFAULTS, options);
}
console.log(JSON.stringify(makeSettings({ layout: { columns: 3 } })));
</script>{"theme":"light","layout":{"columns":3,"gap":8}}Key points
- $.extend(target, a, b) copies properties into target; pass true first for a deep merge; $.extend({}, defaults, options) is the classic settings pattern.
- $.each(), $.map() and $.grep() loop over, transform and filter arrays and objects.
- $.isPlainObject(), $.isEmptyObject() and $.contains() answer common questions about values and elements.
- jQuery 4 removed $.trim, $.isArray, $.isFunction, $.isNumeric, $.type, $.parseJSON and $.now; use the built-in JavaScript equivalents.