[{"data":1,"prerenderedAt":174},["ShallowReactive",2],{"qa-\u002Fjavascript\u002Farrays\u002Fdestructuring-spread":3},{"page":4,"siblings":158,"blog":171},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"related":149,"seo":150,"seoDescription":151,"stem":152,"subtopic":153,"topic":154,"topicSlug":155,"updated":156,"__hash__":157},"qa\u002Fjavascript\u002Farrays\u002Fdestructuring-spread.md","Destructuring Spread",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","JavaScript","javascript",{},true,4,"\u002Fjavascript\u002Farrays\u002Fdestructuring-spread",[23,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,97,101,105,109,113,117,121,125,129,133,137,141,145],{"id":24,"difficulty":25,"q":26,"a":27},"array-destructuring-basics","easy","What is array destructuring?","**Array destructuring** unpacks values from an array into distinct\nvariables by **position**, using a pattern on the left of `=`.\n\n```js\nconst [first, second] = [10, 20]\nfirst   \u002F\u002F 10\nsecond  \u002F\u002F 20  assigned by index, not name\n```\n\nIt works on any iterable, not just arrays — strings, Sets, Maps, and\ngenerators all destructure positionally.\n",{"id":29,"difficulty":25,"q":30,"a":31},"skipping-elements","How do you skip elements while destructuring?","Leave an **empty slot** (just a comma) for each element you want to skip.\n\n```js\nconst [, , third] = ['a', 'b', 'c']\nthird   \u002F\u002F 'c'  first two skipped\n```\n\nEach comma consumes one position. It's readable for one skip; for several,\nconsider naming with an underscore convention or indexing directly to keep\nit clear.\n",{"id":33,"difficulty":25,"q":34,"a":35},"default-values","How do default values work in array destructuring?","A default applies only when the matched value is **`undefined`** (not for\n`null` or other falsy values).\n\n```js\nconst [a = 1, b = 2] = [10]\na  \u002F\u002F 10\nb  \u002F\u002F 2   undefined -> default\n\nconst [c = 5] = [null]\nc  \u002F\u002F null  null is not undefined, no default\n```\n\nMissing array positions read as `undefined`, which is exactly why defaults\nkick in there.\n",{"id":37,"difficulty":25,"q":38,"a":39},"swapping-variables","How do you swap two variables with destructuring?","Build an array literal on the right and destructure it on the left — no\ntemp variable needed.\n\n```js\nlet a = 1, b = 2\n[a, b] = [b, a]\na  \u002F\u002F 2\nb  \u002F\u002F 1\n```\n\nThe right side is fully evaluated before assignment, so the swap is\natomic. Watch out: if the previous line lacks a semicolon, the leading\n`[` can be parsed as indexing — start the line with a semicolon if unsure.\n",{"id":41,"difficulty":14,"q":42,"a":43},"nested-destructuring","How do you destructure nested arrays?","Mirror the structure with nested patterns.\n\n```js\nconst [[a, b], [c]] = [[1, 2], [3]]\na  \u002F\u002F 1\nb  \u002F\u002F 2\nc  \u002F\u002F 3\n```\n\nYou can mix in defaults and skips at any level. Deeply nested patterns get\nhard to read fast — destructure one level and name intermediates if it\nstops being obvious.\n",{"id":45,"difficulty":14,"q":46,"a":47},"rest-element","What is the rest element in array destructuring?","A trailing **`...name`** collects all remaining elements into a **new\narray**.\n\n```js\nconst [head, ...tail] = [1, 2, 3, 4]\nhead  \u002F\u002F 1\ntail  \u002F\u002F [2, 3, 4]  a real array\n```\n\nThe rest element must be **last** — `const [...rest, last]` is a\nSyntaxError. It always produces an array, even if empty.\n",{"id":49,"difficulty":14,"q":50,"a":51},"rest-vs-spread","What's the difference between rest and spread, since both use ...?","Same syntax, opposite jobs. **Rest** *collects* multiple elements into one\narray (on the left, in a pattern). **Spread** *expands* one iterable into\nmultiple elements (on the right, in a literal or call).\n\n```js\nconst [first, ...rest] = arr      \u002F\u002F rest: gather\nconst copy = [...arr]             \u002F\u002F spread: expand\n```\n\nPosition is the tell: `...` on the binding side = rest; `...` on the value\nside = spread.\n",{"id":53,"difficulty":25,"q":54,"a":55},"spread-copy","How do you copy an array with spread, and what kind of copy is it?","`[...arr]` produces a **shallow copy** — a new top-level array whose\nelements are the same references.\n\n```js\nconst a = [{ x: 1 }, 2]\nconst b = [...a]\nb === a       \u002F\u002F false  new array\nb[0] === a[0] \u002F\u002F true   inner object still shared\n```\n\nFor nested data you need a deep copy: `structuredClone(a)`.\n",{"id":57,"difficulty":25,"q":58,"a":59},"spread-merge","How do you concatenate arrays with spread?","Spread each array into a new literal, in the order you want.\n\n```js\nconst merged = [...a, ...b, ...c]   \u002F\u002F flat concatenation\nconst withExtras = [0, ...a, 99]    \u002F\u002F insert around them\n```\n\nIt reads more clearly than `a.concat(b, c)` and lets you interleave\nindividual elements, though `concat` can be marginally faster for very\nlarge arrays.\n",{"id":61,"difficulty":14,"q":62,"a":63},"spread-vs-concat","When would you use concat instead of spread?","Functionally similar for merging, but **`concat`** has two edge behaviors\nspread doesn't: it can append non-array values directly, and it's often\nfaster for huge arrays since the engine doesn't iterate element-by-element.\n\n```js\n[1, 2].concat(3, [4, 5])   \u002F\u002F [1, 2, 3, 4, 5]  mixes values and arrays\n[...[1,2], 3, ...[4,5]]    \u002F\u002F same result via spread\n```\n\nUse spread for readability and interleaving; reach for `concat` in hot\npaths over large arrays.\n",{"id":65,"difficulty":14,"q":66,"a":67},"spread-iterables","What can you spread besides arrays?","Anything **iterable**: strings, `Set`, `Map`, `arguments`, NodeLists,\ngenerators.\n\n```js\n[...'abc']            \u002F\u002F ['a', 'b', 'c']  string -> chars\n[...new Set([1,1,2])] \u002F\u002F [1, 2]\n[...map.entries()]    \u002F\u002F [[k, v], ...]\n```\n\nPlain objects are **not** iterable, so `[...{a:1}]` throws. Use\n`Object.values`\u002F`entries` to turn an object into an iterable first.\n",{"id":69,"difficulty":14,"q":70,"a":71},"spread-string-chars","Why is [...str] safer than str.split('') for splitting characters?","Spread iterates by **code point** (respecting surrogate pairs), while\n`split('')` splits by UTF-16 **code unit**, breaking emoji and other\nastral characters.\n\n```js\n[...'a😀b']          \u002F\u002F ['a', '😀', 'b']  ✅\n'a😀b'.split('')     \u002F\u002F ['a', '\\ud83d', '\\ude00', 'b']  ❌ broken\n```\n\nPrefer spread (or `Array.from`) whenever input might contain non-BMP\ncharacters.\n",{"id":73,"difficulty":25,"q":74,"a":75},"spread-function-args","How do you pass an array as separate arguments?","Spread it in the call site — it replaces the old `Function.prototype.apply`\npattern.\n\n```js\nconst nums = [5, 1, 9]\nMath.max(...nums)        \u002F\u002F 9\nMath.max.apply(null, nums) \u002F\u002F old way\n```\n\nYou can also mix fixed and spread args: `fn(a, ...rest, b)`. One caveat:\nspreading a very large array (100k+) can hit argument-count limits — loop\nor `reduce` instead.\n",{"id":77,"difficulty":14,"q":78,"a":79},"rest-parameters-vs-destructuring","How does a rest element differ from rest parameters?","They look identical but live in different places. A **rest element**\nappears in a destructuring pattern and gathers leftover array items; **rest\nparameters** appear in a function signature and gather leftover arguments.\n\n```js\nconst [a, ...rest] = arr            \u002F\u002F rest element\nfunction f(first, ...others) {}     \u002F\u002F rest parameters\n```\n\nBoth produce real arrays (unlike the old `arguments` object), and both must\nbe last.\n",{"id":81,"difficulty":14,"q":82,"a":83},"destructure-in-params","How do you destructure an array in a function parameter?","Put the pattern directly in the parameter list — handy for functions\nreceiving coordinate pairs or `Object.entries` items.\n\n```js\nfunction dist([x1, y1], [x2, y2]) {\n  return Math.hypot(x2 - x1, y2 - y1)\n}\ndist([0, 0], [3, 4])   \u002F\u002F 5\n```\n\nAdd a default for the whole parameter (`= []`) if it might be missing,\notherwise destructuring `undefined` throws.\n",{"id":85,"difficulty":14,"q":86,"a":87},"destructure-in-loops","How is array destructuring used in for...of loops?","Destructure each iterated item inline — extremely common with\n`entries()` and `Object.entries`.\n\n```js\nfor (const [i, value] of arr.entries()) {\n  console.log(i, value)   \u002F\u002F index and value\n}\nfor (const [key, val] of Object.entries(obj)) { \u002F* ... *\u002F }\n```\n\nIt keeps the loop body clean versus indexing into a pair with `[0]`\u002F`[1]`.\n",{"id":89,"difficulty":14,"q":90,"a":91},"swap-array-elements","How do you swap two elements within an array?","Destructure the two positions on the left and provide them swapped on the\nright.\n\n```js\nconst a = [1, 2, 3, 4]\n;[a[1], a[3]] = [a[3], a[1]]\na   \u002F\u002F [1, 4, 3, 2]\n```\n\nAs with variable swaps, lead with a semicolon when the previous statement\ndoesn't end in one, so `[` isn't read as indexing.\n",{"id":93,"difficulty":94,"q":95,"a":96},"default-from-other","hard","Can a destructuring default reference an earlier bound variable?","Yes — defaults are evaluated **left to right**, so a later default can use\nan already-assigned earlier one.\n\n```js\nconst [a = 1, b = a * 2] = []\na  \u002F\u002F 1\nb  \u002F\u002F 2   b's default used a\n```\n\nReferencing a variable that hasn't been bound *yet* (to its right) throws a\ntemporal-dead-zone error. Keep dependencies left-to-right.\n",{"id":98,"difficulty":14,"q":99,"a":100},"destructure-undefined","What happens when you destructure null or undefined?","Both throw a **TypeError**, because destructuring tries to read the\niterator (`Symbol.iterator`) off the value.\n\n```js\nconst [a] = null        \u002F\u002F TypeError\nconst [b] = undefined   \u002F\u002F TypeError\nconst [c] = []          \u002F\u002F c is undefined (empty but iterable)\n```\n\nGuard with a default at the source: `const [c] = maybeArr ?? []`.\n",{"id":102,"difficulty":94,"q":103,"a":104},"spread-shallow-pitfall","What's the classic bug with spreading nested arrays?","People assume `[...arr]` deep-copies, but inner arrays\u002Fobjects stay shared,\nso mutating them mutates the \"copy\" too.\n\n```js\nconst matrix = [[1], [2]]\nconst copy = [...matrix]\ncopy[0].push(99)\nmatrix[0]   \u002F\u002F [1, 99]  original changed\n```\n\nFor grids\u002Fnested structures use `matrix.map(row => [...row])` (one level)\nor `structuredClone(matrix)` (any depth).\n",{"id":106,"difficulty":14,"q":107,"a":108},"array-from-vs-spread","When is Array.from better than spread?","`Array.from` accepts a **mapping function** and works on **array-like**\nobjects (those with `length` but no `Symbol.iterator`), which spread can't\nhandle.\n\n```js\nArray.from({ length: 3 }, (_, i) => i)  \u002F\u002F [0, 1, 2]  array-like + map\n[...{ length: 3 }]                       \u002F\u002F TypeError, not iterable\n```\n\nUse spread for iterables and brevity; use `Array.from` for array-likes or\nwhen you want to map during creation.\n",{"id":110,"difficulty":14,"q":111,"a":112},"clone-and-modify","How do you immutably add or remove an item using spread?","Build a new array around the change instead of mutating.\n\n```js\nconst added   = [...arr, item]                 \u002F\u002F append\nconst prepend = [item, ...arr]                 \u002F\u002F prepend\nconst removed = [...arr.slice(0, i), ...arr.slice(i + 1)]  \u002F\u002F remove at i\n```\n\nThis is the standard pattern for React\u002FRedux state. The ES2023\n`arr.with(i, val)` and `toSpliced` cover replace\u002Fremove even more cleanly.\n",{"id":114,"difficulty":14,"q":115,"a":116},"spread-order-matters","Does the order of spread elements matter?","Yes — elements land in source order, so later items can override or follow\nearlier ones.\n\n```js\n[...a, ...b]   \u002F\u002F a's items first, then b's\n[...b, ...a]   \u002F\u002F reversed grouping\n```\n\nUnlike object spread (where later keys win), array spread doesn't\n\"override\" — every element is kept; only the resulting positions differ.\n",{"id":118,"difficulty":94,"q":119,"a":120},"nested-default-skip-combo","Can you combine skipping, defaults, and rest in one pattern?","Yes — they compose freely, as long as rest stays last.\n\n```js\nconst [, second = 0, ...rest] = [1]\nsecond  \u002F\u002F 0     (skipped first, defaulted missing second)\nrest    \u002F\u002F []    nothing left\n```\n\nPowerful but easy to over-pack; if a single pattern needs all three, it's\noften clearer to split into a couple of statements.\n",{"id":122,"difficulty":25,"q":123,"a":124},"destructure-return-values","How is array destructuring used to return multiple values?","A function returns an array (or tuple-like) and the caller destructures it\npositionally — the pattern behind React's `useState`.\n\n```js\nfunction minMax(arr) {\n  return [Math.min(...arr), Math.max(...arr)]\n}\nconst [lo, hi] = minMax([3, 1, 9])   \u002F\u002F lo=1, hi=9\n```\n\nUse array returns when order is meaningful and stable; prefer an object\nreturn when callers should pick fields by name.\n",{"id":126,"difficulty":25,"q":127,"a":128},"spread-set-dedupe","How do you dedupe an array with spread and a Set?","Wrap in a `Set` (drops duplicates by SameValueZero), then spread back to an\narray.\n\n```js\nconst unique = [...new Set([1, 1, 2, 3, 3])]  \u002F\u002F [1, 2, 3]\n```\n\nIt preserves first-seen order and is the idiomatic one-liner. Note it\ndedupes by reference for objects, so identical-looking objects won't\ncollapse.\n",{"id":130,"difficulty":14,"q":131,"a":132},"flatten-with-spread","Can you flatten an array of arrays with spread?","For a known, small number of arrays, yes. For an arbitrary array of\narrays, prefer **`flat`** or `reduce`.\n\n```js\n[...a, ...b]                 \u002F\u002F fine for a fixed set\n[[1],[2],[3]].flat()         \u002F\u002F [1, 2, 3]  arbitrary length\nrows.reduce((acc, r) => [...acc, ...r], [])  \u002F\u002F works but O(n²)\n```\n\nThe `reduce`-with-spread version reallocates each step — use `flat()` or\n`acc.push(...r)` for performance.\n",{"id":134,"difficulty":25,"q":135,"a":136},"spread-max-min","How do you find the max or min of an array?","Spread the array into `Math.max`\u002F`Math.min`.\n\n```js\nMath.max(...[3, 9, 1])  \u002F\u002F 9\nMath.min(...[3, 9, 1])  \u002F\u002F 1\n```\n\nCaveat: `Math.max()` of an **empty** array is `-Infinity` (and `min` is\n`Infinity`), and spreading a massive array may exceed argument limits — use\n`reduce` for those cases.\n",{"id":138,"difficulty":25,"q":139,"a":140},"ignore-with-underscore","How do you conventionally ignore destructured values you don't need?","Either skip with an empty slot, or bind to a throwaway name like `_`.\n\n```js\nconst [, , third] = list       \u002F\u002F skip slots\nconst [_a, _b, third2] = list  \u002F\u002F name-but-ignore convention\n```\n\nThe underscore is just a normal variable (linters often allow an `_`\nprefix to mean \"unused\"). Skipping slots avoids creating bindings at all.\n",{"id":142,"difficulty":94,"q":143,"a":144},"destructure-generator","What happens when you destructure a generator or infinite iterable?","Destructuring pulls only as many values as the pattern needs and then\nstops — so it works on **infinite** iterables.\n\n```js\nfunction* naturals() { let n = 1; while (true) yield n++ }\nconst [a, b, c] = naturals()\na, b, c   \u002F\u002F 1, 2, 3   only three pulled\n```\n\nBut a **rest element** (`const [first, ...rest]`) would try to drain the\nwhole iterable and hang forever — never use rest on an infinite source.\n",{"id":146,"difficulty":94,"q":147,"a":148},"swap-without-temp-perf","Is destructuring swap as fast as a temp variable?","Functionally identical; performance is essentially the same in modern\nengines, though a destructuring swap allocates a small array literal that\nthe optimizer usually elides.\n\n```js\n[a, b] = [b, a]          \u002F\u002F readable, idiomatic\nconst t = a; a = b; b = t \u002F\u002F traditional, zero allocation\n```\n\nPrefer the destructuring form for clarity; only the traditional swap in\nextremely hot numeric loops where you've profiled an actual difference.\n",null,{"description":11},"JavaScript array destructuring and spread interview questions — defaults, skipping, swapping, nested patterns, rest elements, copying and merging arrays, spread vs concat and consuming iterables.","javascript\u002Farrays\u002Fdestructuring-spread","Array Destructuring & Spread","Arrays & Iteration","arrays","2026-06-18","dwUK35g8bIJziTXcSu72Y0e_b_MJftZi1sERh1noiQ0",[159,163,166,170],{"subtopic":160,"path":161,"order":162},"Array Methods","\u002Fjavascript\u002Farrays\u002Farray-methods",1,{"subtopic":164,"path":165,"order":12},"Mutating vs Non-Mutating","\u002Fjavascript\u002Farrays\u002Fmutating-vs-nonmutating",{"subtopic":167,"path":168,"order":169},"Searching & Sorting","\u002Fjavascript\u002Farrays\u002Fsearching-sorting",3,{"subtopic":153,"path":21,"order":20},{"path":172,"title":173},"\u002Fblog\u002Fjavascript-array-destructuring-spread","JavaScript Array Destructuring & Spread — Unpacking, Copying and Combining Arrays",1781808676266]