Advanced JavaScript Patterns
Explore symbols, proxies, reflection, property descriptors, currying, memoization, debouncing, throttling, and metaprogramming.
Symbols and Well-Known Symbols
Symbols provide unique primitive values that can be used as property keys. Two separately created symbols are different even if they have the same description. Well-known symbols such as Symbol.iterator allow JavaScript objects to participate in language protocols.
Symbols are useful when you need non-string property keys or want to integrate with built-in language behavior.
const id = Symbol('id');
const user = {
name: 'Suriya',
[id]: 123
};
console.log(user[id]);- Symbols are unique primitive values.
- Symbols can be object property keys.
- Well-known symbols customize language protocols.
What is a key property of Symbol values?
Property Descriptors and Object.defineProperty
Property descriptors control attributes such as writable, enumerable, and configurable for data properties. Accessor properties use get and set instead of a direct value.
Object.defineProperty exposes this lower-level object model and is useful for libraries, polyfills, and controlled APIs.
const config = {};
Object.defineProperty(config, 'version', {
value: '1.0.0',
writable: false,
enumerable: true,
configurable: false
});
console.log(config.version);- Property descriptors control property behavior.
- Data descriptors and accessor descriptors have different fields.
- defineProperty enables precise object API design.
Which descriptor controls whether a data property's value can be changed by assignment?
Proxy and Reflect
A Proxy wraps an object and intercepts operations such as property reads, writes, function calls, and construction. Reflect provides standardized methods for performing many fundamental object operations.
Proxies power advanced abstractions such as reactive systems, validation layers, and virtualization, but they can also make behavior harder to reason about and may introduce performance overhead.
const user = {
name: 'Suriya'
};
const proxy = new Proxy(user, {
get(target, property, receiver) {
console.log('Reading', property);
return Reflect.get(target, property, receiver);
}
});
console.log(proxy.name);- Proxy intercepts fundamental object operations.
- Reflect provides standard mechanisms for performing those operations.
- Proxies are powerful but should be used intentionally.
What is a Proxy primarily used for?
Memoization
Memoization caches the result of a function based on its inputs. It is most useful for deterministic or pure computations where repeated inputs are common and the cost of computing the result is significant.
Memoization has a tradeoff: it exchanges memory for computation. An unbounded memoization cache can itself become a memory problem.
function memoize(fn) {
const cache = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) return cache.get(key);
const result = fn(...args);
cache.set(key, result);
return result;
};
}
const square = memoize(n => n * n);
console.log(square(10));
console.log(square(10));- Memoization trades memory for computation.
- It works best for deterministic computations.
- Cache growth and key design must be considered.
What does memoization primarily trade for faster repeated calculations?
Debouncing and Throttling
Debouncing delays execution until a burst of calls stops for a specified period. It is useful for search inputs and resize handling. Throttling limits execution to at most a certain frequency, useful for scroll or pointer events.
The correct choice depends on whether you care about the final event after a burst or continuous periodic updates.
function debounce(fn, delay) {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => fn(...args), delay);
};
}
const search = debounce(query => {
console.log('Searching:', query);
}, 300);- Debounce waits for inactivity.
- Throttle limits execution frequency.
- Both are useful for high-frequency events.
Which technique is best suited to run a search only after the user stops typing briefly?