Build a chainable jQuery-style $ wrapper over multiple DOM nodes
Implement a $(selector) helper returning a wrapper whose methods chain over every matched node: $('.item').addClass('on').css({ color: 'red' }).html('<b>hi</b>'). Provide addClass(c), removeClass(c), css(obj), and html(s), each applied to ALL matched elements and each returning the wrapper for chaining. Select with querySelectorAll.
const $ = (selector) => new DomWrapper(selector);
class DomWrapper {
constructor(selector) {
this.elements = document.querySelectorAll(selector);
}
addClass(c) {
// your code here
}
}
Write the implementation.
Store the querySelectorAll result on the instance. Each method loops over this.elements applying the change — classList.add/remove, Object.entries(obj) into el.style, el.innerHTML = s — then return this so the wrapper chains. The methods live once on the class prototype rather than being recreated per element, and one call fans the operation across the whole matched set.
- ✗Using
querySelector(one node) when the API must operate on every matched element - ✗Forgetting
return this, so the second method in the chain has no wrapper to call on - ✗Recreating the wrapper or methods per element instead of defining them once on the class
- →Why is a class wrapper more efficient than returning a fresh object of methods on each
$()call? - →How does
return thisover a node list let one call fan an operation across many elements?
Solution
The class stores the node list; each method loops over it and returns this.
const $ = (selector) => new DomWrapper(selector);
class DomWrapper {
constructor(selector) {
this.elements = document.querySelectorAll(selector);
}
addClass(c) {
for (const el of this.elements) el.classList.add(c);
return this;
}
removeClass(c) {
for (const el of this.elements) el.classList.remove(c);
return this;
}
css(obj) {
for (const el of this.elements) {
for (const [k, v] of Object.entries(obj)) el.style[k] = v;
}
return this;
}
html(s) {
for (const el of this.elements) el.innerHTML = s;
return this;
}
}
$('.item').addClass('on').css({ color: 'red' }).html('<b>hi</b>');
How it works
$() creates one DomWrapper instance that remembers the querySelectorAll result — all matched nodes. Each method loops over this.elements and applies the change to every one, then returns this. Returning the same wrapper is the chaining mechanism: the next call operates on the same node set.
A class wrapper is more efficient than returning a fresh object of methods on each $() call: the methods are defined once on the DomWrapper prototype rather than recreated. A single call such as addClass fans the operation out across all matched elements at once. </content>