| technology | JavaScript | |||||
|---|---|---|---|---|---|---|
| domain | frontend | |||||
| level | Senior/Architect | |||||
| version | ES2024+ | |||||
| tags |
|
|||||
| ai_role | Senior JavaScript Expert | |||||
| last_updated | 2026-03-22 |
- Primary Goal: Detail advanced and niche topics in JavaScript for high-performance applications.
- Target Tooling: Cursor, Windsurf, Antigravity.
- Tech Stack Version: ES2024+
Note
Context: Long-lived applications (SPAs).
window.addEventListener('resize', () => this.handleResize());
// Component unmounts, but listener remainsThe event listener keeps a reference to the component/context, preventing garbage collection even after the component is destroyed.
const handler = () => this.handleResize();
window.addEventListener('resize', handler);
// Cleanup:
window.removeEventListener('resize', handler);Always remove event listeners in cleanup phases (e.g., componentWillUnmount or useEffect return). Use AbortController for an even more modern approach to listener cleanup.
Note
Context: Managing temporal background tasks.
setInterval(() => {
fetchStatus();
}, 1000);Intervals continue to run indefinitely until the page is closed, even if the data they process is no longer needed, consuming CPU and memory.
const intervalId = setInterval(fetchStatus, 1000);
// Later:
clearInterval(intervalId);Store the ID returned by setTimeout or setInterval and clear it when the task is no longer relevant.
Note
Context: Understanding the Event Loop and closure capture.
for (var i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100); // Prints '5' five times
}var is function-scoped. By the time the setTimeout executes, the loop has finished and i is 5. Each closure shares the same reference to i.
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100); // Prints 0, 1, 2, 3, 4
}Use let in loop headers. It creates a new binding for each iteration, ensuring the closure captures the value of i at that specific moment.
Note
Context: Ensuring useful stack traces.
throw 'Something went wrong';Throwing a string provides no stack trace. It makes it nearly impossible to determine where the error originated in a complex call stack.
throw new Error('Something went wrong');Always throw an instance of Error (or a subclass). This captures the stack property, which is vital for debugging.
Note
Context: Ecosystem compatibility and stability.
Array.prototype.last = function() {
return this[this.length - 1];
};"Monkey patching" built-ins can lead to collisions if a future ECMAScript version implements a method with the same name but different behavior. It also breaks for-in loops if not handled carefully.
const last = (arr) => arr[arr.length - 1];Use utility functions or wrapper classes instead of modifying global prototypes.
Note
Context: Readability vs Micro-benchmarks.
const floor = ~~x; // Double bitwise NOT to floorWhile ~~ is slightly faster in some engines, it makes the code cryptic. It also only works for numbers within the 32-bit integer range.
const floor = Math.floor(x);Prioritize readability. Modern JIT compilers are smart enough to optimize Math.floor. Only use bitwise tricks if profiling proves it's a critical bottleneck in a hot path.
⚡ 37. V8 Hidden Classes: Changing object shape after initialization
Note
Context: V8 JIT optimization.
function User(name) {
this.name = name;
}
const u1 = new User('Alice');
u1.age = 25; // Dynamically adding propertyV8 creates "Hidden Classes" to optimize object property access. Adding properties after initialization changes the "shape" of the object, causing V8 to drop to a slower "Dictionary Mode" for that object.
function User(name, age) {
this.name = name;
this.age = age;
}
const u1 = new User('Alice', 25);Initialize all object properties in the constructor or a factory function. Maintain a consistent object "shape" to keep V8 in the optimized path.
Note
Context: Memory allocation and JIT optimization.
const arr = new Array(100);
arr[50] = 'val';Creating "holes" in arrays makes them "sparse". Sparse arrays are stored differently (as hash maps) which is much slower for iteration and access than "packed" arrays.
const arr = Array.from({ length: 100 }, () => null);Initialize arrays with default values (like null or 0) instead of leaving empty slots. This keeps the array in "packed" mode.
Note
Context: Security and performance.
const result = eval('2 + 2');eval() executes strings as code, opening a massive XSS security vulnerability if the string contains user input. It also prevents the JIT compiler from optimizing the surrounding scope.
const result = new Function('a', 'b', 'return a + b')(2, 2); // Slightly better, but still risky
// Better:
const operations = { '+': (a, b) => a + b };Avoid eval(). Use lookup tables, JSON parsing, or safe math libraries to handle dynamic logic.
Note
Context: Maintaining a healthy codebase.
for (let i = 0, len = arr.length; i < len; i++) { /* ... */ }Caching arr.length was necessary 15 years ago. Today, modern engines optimize this automatically. Adding extra variables for micro-gains makes the code harder to read.
for (const item of arr) { /* ... */ }Focus on "Big O" complexity and deterministic, strictly typed code. Only micro-optimize after profiling identifies a specific performance hotspot.