Spread & Rest Operators
debt(d5/e3/b3/t7)
Closest to 'specialist tool catches it' (d5). ESLint can detect spread-in-hot-loop patterns and shallow-copy assumptions via rules like no-object-spread-in-hot-path (custom/plugin), but the canonical misconception (shallow vs. deep clone) requires code review or runtime testing to catch reliably. Default linters don't flag the shallow-copy trap automatically.
Closest to 'simple parameterised fix' (e3). The quick_fix is explicit: replace `{...obj}` with `structuredClone(obj)` when deep copy is needed. This is a one-to-one substitution within a single expression, no cross-file refactoring required. Performance issues in loops require relocating spread outside the loop or restructuring iteration logic.
Closest to 'localised tax' (b3). Spread and rest are localized syntactic choices within function signatures or object literals. They don't impose system-wide coupling or architectural debt. The burden is cognitive (understanding shallow vs. deep) rather than structural. Each usage site is independent; poor choices don't cascade or force future refactors.
Closest to 'serious trap' (t7). The misconception field explicitly states the trap: developers assume `{...obj}` creates a deep clone (as some might expect from the intuitive name 'spread'), but it only spreads top-level properties, leaving nested objects as shared references. This directly contradicts intuition and is a documented gotcha that most JS developers eventually learn through painful debugging.
Also Known As
TL;DR
Explanation
Spread: [...arr] clones array, {...obj} shallow-clones object, fn(...args) spreads into call. Rest: function fn(first, ...rest) collects remaining params. Object spread for merging: {...defaults, ...overrides} — later keys win, parallel to array_merge($defaults, $overrides) in PHP. Spread copies shallow — nested objects are still references. Object spread is not available in PHP natively without spread operator RFC.
Common Misconception
Why It Matters
Common Mistakes
- Assuming {...obj} deep-clones nested objects
- Using spread in performance-critical loops — creates new objects each iteration
- Rest parameters confused with arguments object
Code Examples
// Mutates original nested object:
const config = { db: { host: 'localhost' } };
const override = { ...config, extra: true };
override.db.host = 'prod'; // Also mutates config.db.host!
// Shallow clone — fine for flat objects:
const merged = { ...defaults, ...userConfig };
// Deep clone when needed:
const deepClone = structuredClone(config);
// Rest parameters:
function log(level, ...messages) {
messages.forEach(m => console[level](m));
}