| date | 2025-05-06 07:45:22 +0530 |
|---|---|
| description | Intercepts array mutations to dispatch custom events when push is called. Enables reactive arrays without frameworks or proxies. |
| premium | true |
JavaScript arrays are powerful—but they don’t emit events . Want to react when someone .push()es a new item? You’re out of luck... unless you take control.
This post shows you how to intercept array mutations and dispatch custom events when push() is called — all in vanilla JavaScript, no frameworks, no proxies.
We want to monitor this:
myArray.push("newItem");And react like this:
document.addEventListener("arrayPush", e => {
console.log("Pushed:", e.detail);
});function createObservableArray(initial = []) {
const arr = [...initial];
arr.push = function (...items) {
const result = Array.prototype.push.apply(this, items);
const event = new CustomEvent("arrayPush", {
detail: {
added: items,
newLength: this.length
}
});
document.dispatchEvent(event);
return result;
};
return arr;
}const myArray = createObservableArray();
document.addEventListener("arrayPush", (e) => {
console.log("Array was pushed:", e.detail);
});
myArray.push("alpha");
// logs: { added: ["alpha"], newLength: 1 }
myArray.push("beta", "gamma");
// logs: { added: ["beta", "gamma"], newLength: 3 }- We're overriding
push()on a per-array basis - We preserve original functionality via
Array.prototype.push.apply(...) - We dispatch a
CustomEventwith rich detail
Want to observe pop, shift, or even splice? Here’s a sketch:
function makeObservable(arr, methods = ["push"]) {
for (const method of methods) {
const original = arr[method];
arr[method] = function (...args) {
const result = original.apply(this, args);
document.dispatchEvent(new CustomEvent(`array:${method}`, {
detail: { args, result, current: [...this] }
}));
return result;
};
}
return arr;
}const list = makeObservable([]);
document.addEventListener("array:push", e => console.log("Pushed", e.detail));
document.addEventListener("array:pop", e => console.log("Popped", e.detail));
list.push("x");
list.pop();Want a more general-purpose reactive array? Use a Proxy. It’s more powerful but less performant:
function reactiveArray(arr = []) {
return new Proxy(arr, {
get(target, prop) {
if (prop === "push") {
return (...items) => {
const result = Array.prototype.push.apply(target, items);
document.dispatchEvent(new CustomEvent("arrayPush", {
detail: { added: items }
}));
return result;
};
}
return Reflect.get(target, prop);
}
});
}You don’t need Vue or MobX to detect array changes. With just a few lines of JavaScript, you can:
- Intercept native behavior
- Dispatch clean, custom events
- Build observability into data structures
This pattern is a foundation for reactive state systems, event-driven logic, or any scenario where "changes should trigger actions."
Want a React-compatible or Svelte-integrated version? Ask and I'll tailor one.
- By using Object.defineProperty
- By overriding the push method on the specific array instance
- By modifying Array.prototype directly
- By using a Proxy on all arrays
- To make the code shorter
- To avoid using the spread operator
- To call the original push functionality while preserving context
- To improve performance
- Only the array length
- The entire array
- The added items and the new array length
- The timestamp of the push