Let’s be honest — most lists titled “mind-blowing JavaScript tricks” just rehash ES6 basics like destructuring or let
and const
.
This post goes deeper. Below are 10 lesser-known JavaScript tricks — ranging from clever patterns to powerful built-ins — that can seriously level up your JS game.
1. ❄️ Deep Freeze: Make Objects Fully Immutable
Want to prevent accidental mutations in deeply nested objects? Try this:
function deepFreeze(obj) {
Object.freeze(obj);
Object.getOwnPropertyNames(obj).forEach(prop => {
if (
typeof obj[prop] === 'object' &&
obj[prop] !== null &&
!Object.isFrozen(obj[prop])
) {
deepFreeze(obj[prop]);
}
});
return obj;
}
🔐 Perfect for state management in Redux or Vuex.
2. 🔁 Closures for Private State
JavaScript doesn’t have native private variables, but closures get the job done:
const counter = (() => {
let count = 0;
return () => ++count;
})();
counter(); // 1
counter(); // 2
No one can touch count
from the outside. It’s safe and scoped.
3. 🕵️ Intercept Everything with Proxies
Proxies let you trap operations like reading, writing, or deleting properties.
const watched = new Proxy({}, {
get(target, prop) {
console.log(`Accessing ${prop}`);
return target[prop];
},
set(target, prop, value) {
console.log(`Setting ${prop} = ${value}`);
target[prop] = value;
return true;
}
});
watched.name = 'Basit'; // Logs: Setting name = Basit
watched.name; // Logs: Accessing name
Use cases: validation, reactivity (like Vue), auto-tracking, etc.
4. 🧠 Currying: Break Down Your Functions
Currying transforms a multi-arg function into a sequence of single-arg functions:
const multiply = a => b => a * b;
const double = multiply(2);
double(5); // 10
💡 Excellent for functional pipelines and partial application.
5. 🚦 Asynchronous Iteration with for await...of
Want to loop over promises or async data streams?
const urls = ['https://api1.com', 'https://api2.com'];
for await (const res of urls.map(fetch)) {
const data = await res.json();
console.log(data);
}
Handles promises one at a time — sequentially.
6. 🪝 Monkey Patch Carefully
While dangerous in shared environments, monkey patching can be useful in isolated scopes:
Array.prototype.last = function () {
return this[this.length - 1];
};
[1, 2, 3].last(); // 3
✋ Only do this in fully controlled codebases. Avoid patching built-ins globally in libraries.
7. 🌀 Tail Call Optimization (TCO)
JS supports tail call optimization (in theory), reducing stack usage in recursion:
"use strict";
function factorial(n, acc = 1) {
if (n <= 1) return acc;
return factorial(n - 1, acc * n); // TCO-friendly
}
📝 Supported in Safari and older spec targets, not in V8 (Chrome/Node) — yet.
8. 🧨 Self-Destructing Functions
Run something once, and never again:
const once = fn => {
let called = false;
return (...args) => {
if (!called) {
called = true;
return fn(...args);
}
};
};
const logOnce = once(console.log);
logOnce('Hello'); // Logs
logOnce('World'); // Ignored
Great for one-time init logic, onboarding screens, or analytics pings.
9. 🧬 Flatten Arrays Recursively Without .flat()
Need to flatten an array without using .flat()
?
const flatten = arr =>
arr.reduce((acc, val) =>
acc.concat(Array.isArray(val) ? flatten(val) : val), []
);
flatten([1, [2, [3]], 4]); // [1, 2, 3, 4]
Works in older environments or for full control of depth.
10. 📦 Dynamic Imports for Lazy Loading
Want to reduce your bundle size and only load when necessary?
if (somethingHeavyNeeded) {
import('./heavy-module.js').then(module => {
module.run();
});
}
✅ Supported in modern browsers and Node.js.
🏁 Final Thoughts
JavaScript has layers. Mastering the basics is good — but tapping into these patterns can help you write cleaner, smarter, more efficient code.
Which one of these tricks did you find most useful or surprising?
Got a favorite trick that didn’t make the list? Share it in the comments 👇
Top comments (0)