These JavaScript tips have genuinely improved my code quality. No fluff — just patterns that work.
1. Optional Chaining is Your Best Friend
// Old way - ugly and error-prone
const city = user && user.address && user.address.city;
// Modern way
const city = user?.address?.city;
// With methods
const first = arr?.at(0);
const len = str?.trim()?.length;
2. Nullish Coalescing vs OR
// || uses any falsy value (0, '', false are falsy!)
const count = data.count || 10; // BUG: returns 10 when count is 0
// ?? only triggers on null/undefined
const count = data.count ?? 10; // CORRECT: returns 0 when count is 0
3. Object Destructuring with Defaults
function createUser({
name,
role = 'user',
active = true,
theme = 'light'
} = {}) {
return { name, role, active, theme };
}
// The = {} default allows calling with no arguments
createUser(); // Works!
createUser({ name: 'Alice' }); // { name: 'Alice', role: 'user', active: true, theme: 'light' }
4. Array Methods Over Loops
const users = [
{ name: 'Alice', age: 25, active: true },
{ name: 'Bob', age: 30, active: false },
{ name: 'Charlie', age: 22, active: true }
];
// Get names of active users over 24, sorted alphabetically
const result = users
.filter(u => u.active && u.age > 24)
.map(u => u.name)
.sort();
// Result: ['Alice']
5. Promise.allSettled for Parallel Requests
// Promise.all fails if ANY request fails
// Promise.allSettled waits for all, reports success/failure for each
const results = await Promise.allSettled([
fetch('/api/users'),
fetch('/api/posts'),
fetch('/api/comments')
]);
results.forEach((result, index) => {
if (result.status === 'fulfilled') {
console.log(`Request ${index}: success`);
} else {
console.log(`Request ${index}: failed - ${result.reason}`);
}
});
6. WeakMap for Private Data
const privateData = new WeakMap();
class User {
constructor(name, password) {
privateData.set(this, { password });
this.name = name;
}
checkPassword(input) {
return privateData.get(this).password === input;
}
}
const user = new User('Alice', 'secret123');
console.log(user.checkPassword('secret123')); // true
console.log(user.password); // undefined - truly private!
7. Object.fromEntries for Transformations
const prices = { apple: 1.5, banana: 0.5, cherry: 3.0 };
// Apply 10% discount to all
const discounted = Object.fromEntries(
Object.entries(prices).map(([key, value]) => [key, value * 0.9])
);
// { apple: 1.35, banana: 0.45, cherry: 2.7 }
8. Logical Assignment Operators
// ||= assigns only if left side is falsy
user.role ||= 'guest';
// &&= assigns only if left side is truthy
user.profile &&= updateProfile(user.profile);
// ??= assigns only if left side is null/undefined
config.timeout ??= 3000;
9. Array.at() for Negative Indexing
const arr = [1, 2, 3, 4, 5];
// Old way
const last = arr[arr.length - 1]; // 5
// Modern way
const last = arr.at(-1); // 5
const secondLast = arr.at(-2); // 4
10. Structured Clone for Deep Copy
// JSON.parse(JSON.stringify()) breaks dates, functions, etc.
const shallow = { ...obj }; // Shallow copy only
// Proper deep clone (Node 17+, all modern browsers)
const deep = structuredClone(obj);
11. AbortController for Request Cancellation
async function fetchWithTimeout(url, timeout = 5000) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, { signal: controller.signal });
clearTimeout(timeoutId);
return response.json();
} catch (err) {
if (err.name === 'AbortError') {
throw new Error('Request timed out');
}
throw err;
}
}
12. Generator Functions for Lazy Sequences
function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
const first10 = Array.from({ length: 10 }, () => fib.next().value);
// [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
13. Error Cause for Better Debugging
async function fetchUser(id) {
try {
const data = await db.query('SELECT * FROM users WHERE id = ?', [id]);
return data;
} catch (err) {
throw new Error(`Failed to fetch user ${id}`, { cause: err });
}
}
// Now you can access the original error
try {
await fetchUser(42);
} catch (err) {
console.log(err.message); // "Failed to fetch user 42"
console.log(err.cause); // Original DB error
}
14. Array Grouping with Object.groupBy
const inventory = [
{ name: 'asparagus', type: 'vegetables', quantity: 5 },
{ name: 'bananas', type: 'fruit', quantity: 0 },
{ name: 'cherries', type: 'fruit', quantity: 2 },
{ name: 'carrots', type: 'vegetables', quantity: 1 },
];
const grouped = Object.groupBy(inventory, ({ type }) => type);
// {
// vegetables: [asparagus, carrots],
// fruit: [bananas, cherries]
// }
15. Using console Better
// Group related logs
console.group('User Authentication');
console.log('Checking credentials...');
console.log('Token validated');
console.groupEnd();
// Time operations
console.time('db-query');
await db.query('...');
console.timeEnd('db-query'); // db-query: 23.4ms
// Table for arrays/objects
console.table(users);
// Assert (throws if false)
console.assert(user.id > 0, 'User ID must be positive');
Key Takeaways
- Use
?.and??instead of manual null checks - Prefer
Promise.allSettledwhen you need all results - Use
structuredClonefor deep copies - Embrace new syntax — it's in all modern browsers
Which of these was new to you? Let me know in the comments!
Follow me for weekly JavaScript and web dev tips.
For further actions, you may consider blocking this person and/or reporting abuse
