[{"data":1,"prerenderedAt":592},["ShallowReactive",2],{"topic-javascript-arrays":3},{"framework":4,"topic":15,"subtopics":24},{"id":5,"description":6,"extension":7,"icon":8,"meta":9,"name":10,"order":11,"slug":8,"stem":12,"tier":13,"__hash__":14},"frameworks\u002Fframeworks\u002Fjavascript.yml","Core JavaScript interview questions covering fundamentals, functions and closures, objects and prototypes, classes and OOP, and asynchronous programming with the event loop.","yml","javascript",{},"JavaScript",1,"frameworks\u002Fjavascript",0,"_TjxyYWBq7dftU9YakX_WX1Z4wAHq9uEUUW7wXL0y0c",{"id":16,"description":17,"extension":7,"frameworkSlug":8,"meta":18,"name":19,"order":20,"slug":21,"stem":22,"__hash__":23},"topics\u002Ftopics\u002Fjavascript-arrays.yml","Creating and iterating arrays with map, filter and reduce, mutation versus immutability, searching and sorting, and array destructuring and spread — the everyday tools for working with collections in JavaScript.",{},"Arrays & Iteration",6,"arrays","topics\u002Fjavascript-arrays","eJvg0ZBiFKP3QUymQDEwMgBS_wi33V9eQLpIGNETmEY",[25,177,316,452],{"id":26,"title":27,"body":28,"description":32,"difficulty":35,"extension":36,"framework":10,"frameworkSlug":8,"meta":37,"navigation":38,"order":11,"path":39,"questions":40,"related":171,"seo":172,"seoDescription":173,"stem":174,"subtopic":27,"topic":19,"topicSlug":21,"updated":175,"__hash__":176},"qa\u002Fjavascript\u002Farrays\u002Farray-methods.md","Array Methods",{"type":29,"value":30,"toc":31},"minimark",[],{"title":32,"searchDepth":33,"depth":33,"links":34},"",2,[],"medium","md",{},true,"\u002Fjavascript\u002Farrays\u002Farray-methods",[41,46,50,54,58,62,66,70,74,78,82,86,90,94,98,102,106,111,115,119,123,127,131,135,139,143,147,151,155,159,163,167],{"id":42,"difficulty":43,"q":44,"a":45},"map-basics","easy","What does Array.prototype.map do?","**map** creates a **new array** by calling a callback on every element and\ncollecting the return values. It does not mutate the original and always\nreturns an array of the **same length**.\n\n```js\nconst nums = [1, 2, 3]\nconst doubled = nums.map(n => n * 2) \u002F\u002F [2, 4, 6]\nnums \u002F\u002F [1, 2, 3] — unchanged\n```\n\nA common pitfall is using `map` purely for side effects (logging, pushing\nelsewhere). If you don't use the returned array, use `forEach` instead — it\nsignals intent and avoids allocating a throwaway array.\n",{"id":47,"difficulty":43,"q":48,"a":49},"filter-basics","What does Array.prototype.filter do?","**filter** returns a **new array** containing only the elements for which the\ncallback returns a **truthy** value. Length is less than or equal to the\noriginal.\n\n```js\nconst nums = [1, 2, 3, 4]\nconst evens = nums.filter(n => n % 2 === 0) \u002F\u002F [2, 4]\n```\n\nGotcha: the predicate must return a boolean-ish value. Forgetting `return` in\na block body silently filters everything out, since `undefined` is falsy:\n\n```js\nnums.filter(n => { n % 2 === 0 }) \u002F\u002F [] — no return\n```\n",{"id":51,"difficulty":43,"q":52,"a":53},"foreach-basics","What is forEach used for and what does it return?","**forEach** runs a callback once per element for **side effects**. It always\nreturns **undefined** — you can't chain off it.\n\n```js\n[1, 2, 3].forEach(n => console.log(n))\n```\n\nTwo gotchas: you **cannot break** out of `forEach` (use a `for...of` or `some`\nif you need early exit), and it **skips holes** in sparse arrays. If you need\na transformed result, reach for `map` instead.\n",{"id":55,"difficulty":35,"q":56,"a":57},"reduce-basics","How does Array.prototype.reduce work?","**reduce** folds an array into a **single value** by threading an accumulator\nthrough a callback `(acc, cur) => newAcc`. You pass an **initial value** as the\nsecond argument.\n\n```js\nconst sum = [1, 2, 3, 4].reduce((acc, n) => acc + n, 0) \u002F\u002F 10\n```\n\nPitfall: **omitting the initial value** makes reduce use the first element as\nthe seed and start at index 1 — and it **throws** on an empty array. Always\npass an explicit initial value unless you have a specific reason not to.\n",{"id":59,"difficulty":35,"q":60,"a":61},"reduce-no-initial","What happens if you call reduce without an initial value on an empty array?","It throws a **TypeError: Reduce of empty array with no initial value**. With no\nseed, reduce needs at least one element to start from.\n\n```js\n[].reduce((a, b) => a + b)    \u002F\u002F TypeError\n[].reduce((a, b) => a + b, 0) \u002F\u002F 0\n```\n\nThis is why supplying an initial value is a best practice — it makes the\noperation total (defined for all inputs) and pins down the accumulator's type.\n",{"id":63,"difficulty":35,"q":64,"a":65},"reduceright","What is reduceRight and when would you use it?","**reduceRight** is identical to `reduce` but processes elements from **right to\nleft**. It matters when the operation is **not associative** or when order of\ncomposition matters.\n\n```js\n\u002F\u002F function composition: f(g(h(x)))\nconst compose = (...fns) => x =>\n  fns.reduceRight((acc, fn) => fn(acc), x)\n\nconst f = compose(n => n + 1, n => n * 2)\nf(3) \u002F\u002F 7  -> (3*2)+1\n```\n\nFor plain addition the direction is irrelevant; for string building, division,\nor composition it changes the result.\n",{"id":67,"difficulty":43,"q":68,"a":69},"some-every","What is the difference between some and every?","**some** returns `true` if **at least one** element passes the predicate;\n**every** returns `true` only if **all** elements pass. Both **short-circuit**.\n\n```js\n[1, 2, 3].some(n => n > 2)  \u002F\u002F true  (stops at 3)\n[1, 2, 3].every(n => n > 0) \u002F\u002F true\n[1, 2, 3].every(n => n > 1) \u002F\u002F false (stops at 1)\n```\n\nEdge case: `every` on an **empty array** returns `true` (vacuous truth) and\n`some` returns `false`. This trips people up in validation code.\n",{"id":71,"difficulty":43,"q":72,"a":73},"find-findindex","What is the difference between find and findIndex?","**find** returns the **first element** that satisfies the predicate, or\n`undefined`. **findIndex** returns its **index**, or `-1`.\n\n```js\nconst users = [{ id: 1 }, { id: 2 }]\nusers.find(u => u.id === 2)      \u002F\u002F { id: 2 }\nusers.findIndex(u => u.id === 2) \u002F\u002F 1\nusers.find(u => u.id === 9)      \u002F\u002F undefined\n```\n\nUse `find` when you want the object itself; use `findIndex` when you need the\nposition (e.g. to splice or replace it).\n",{"id":75,"difficulty":35,"q":76,"a":77},"findlast","What do findLast and findLastIndex do?","They mirror `find`\u002F`findIndex` but search from the **end** of the array\nbackward, returning the **last** matching element or its index.\n\n```js\nconst nums = [1, 5, 3, 5, 2]\nnums.findLast(n => n === 5)      \u002F\u002F 5  (the second 5)\nnums.findLastIndex(n => n === 5) \u002F\u002F 3\n```\n\nBefore these (ES2023) you'd reverse a copy or loop manually. They avoid an\nextra `[...arr].reverse().find(...)` allocation and keep the original index\nmeaningful.\n",{"id":79,"difficulty":43,"q":80,"a":81},"indexof-vs-find","When should you use find versus indexOf?","Use **indexOf** for **primitive equality** (it uses strict `===`), and **find**\nwhen you need a **predicate** (matching by a property or condition).\n\n```js\n[10, 20, 30].indexOf(20)              \u002F\u002F 1\nusers.find(u => u.name === 'Ann')     \u002F\u002F predicate match\n```\n\n`indexOf` can't match objects by content, only by reference, so for arrays of\nobjects you almost always want `find`\u002F`findIndex`.\n",{"id":83,"difficulty":35,"q":84,"a":85},"flat","What does Array.prototype.flat do?","**flat** returns a **new array** with sub-array elements concatenated up to a\ngiven **depth** (default `1`). It does not mutate.\n\n```js\n[1, [2, [3, [4]]]].flat()        \u002F\u002F [1, 2, [3, [4]]]\n[1, [2, [3, [4]]]].flat(2)       \u002F\u002F [1, 2, 3, [4]]\n[1, [2, [3]]].flat(Infinity)     \u002F\u002F [1, 2, 3] fully flatten\n```\n\nUse `flat(Infinity)` for arbitrarily nested structures. It also removes empty\nslots in sparse arrays as a side effect.\n",{"id":87,"difficulty":35,"q":88,"a":89},"flatmap","What is flatMap and how does it differ from map then flat?","**flatMap** maps each element then flattens the result by **one level**, in a\nsingle pass. It's equivalent to `map(...).flat()` but more efficient and\nexpressive.\n\n```js\nconst sentences = ['a b', 'c d']\nsentences.flatMap(s => s.split(' ')) \u002F\u002F ['a', 'b', 'c', 'd']\n```\n\nIt only flattens **one level**. A neat trick: returning `[]` from the callback\n**drops** an element, letting flatMap act as a combined map+filter.\n",{"id":91,"difficulty":35,"q":92,"a":93},"array-from","What does Array.from do?","**Array.from** creates a real array from any **iterable** or **array-like**\nobject (one with a `length` and indexed keys). It accepts an optional mapping\nfunction as a second argument.\n\n```js\nArray.from('abc')              \u002F\u002F ['a', 'b', 'c']\nArray.from(new Set([1, 1, 2])) \u002F\u002F [1, 2]\nArray.from({ length: 3 }, (_, i) => i) \u002F\u002F [0, 1, 2]\n```\n\nThe mapping form is handy for generating sequences and avoids creating an\nintermediate array, unlike `[...iterable].map(fn)`.\n",{"id":95,"difficulty":43,"q":96,"a":97},"array-of","Why does Array.of exist when we have the Array constructor?","**Array.of** creates an array from its arguments **consistently**, fixing a\nquirk of `new Array()`: a single numeric argument is treated as a **length**,\nnot an element.\n\n```js\nArray(3)      \u002F\u002F [ \u003C3 empty items> ] — length 3\nArray.of(3)   \u002F\u002F [3]\nArray(1, 2)   \u002F\u002F [1, 2] — but inconsistent with Array(3)\nArray.of(1, 2)\u002F\u002F [1, 2]\n```\n\n`Array.of` always treats arguments as elements, so it's safer in generic code.\n",{"id":99,"difficulty":35,"q":100,"a":101},"entries-keys-values","What do entries, keys, and values return on an array?","They return **array iterators**, not arrays. `keys()` yields indices,\n`values()` yields elements, and `entries()` yields `[index, value]` pairs.\n\n```js\nconst arr = ['a', 'b']\nfor (const [i, v] of arr.entries()) {\n  console.log(i, v) \u002F\u002F 0 'a', then 1 'b'\n}\n[...arr.keys()]   \u002F\u002F [0, 1]\n[...arr.values()] \u002F\u002F ['a', 'b']\n```\n\n`entries()` is the clean way to get the index inside a `for...of` loop without\na manual counter.\n",{"id":103,"difficulty":35,"q":104,"a":105},"chaining","How does method chaining work with array methods?","Because **map**, **filter**, **slice**, and friends each return a **new array**,\nyou can chain them into a readable pipeline.\n\n```js\nconst result = users\n  .filter(u => u.active)\n  .map(u => u.name)\n  .sort() \u002F\u002F active users' names, sorted\n```\n\nTradeoff: each step allocates a new array and does a full pass. For huge arrays\nor hot paths a single `reduce` (or a plain loop) can avoid the intermediate\narrays, at the cost of readability.\n",{"id":107,"difficulty":108,"q":109,"a":110},"reduce-to-object","hard","How do you use reduce to build an object from an array?","Seed the accumulator with `{}` and assign keys as you go. This is the canonical\nway to **index** a list by id.\n\n```js\nconst users = [{ id: 1, name: 'A' }, { id: 2, name: 'B' }]\nconst byId = users.reduce((acc, u) => {\n  acc[u.id] = u\n  return acc\n}, {}) \u002F\u002F { 1: {...}, 2: {...} }\n```\n\nFor this exact case, `Object.fromEntries(users.map(u => [u.id, u]))` is often\nclearer. Reserve reduce-to-object for logic that doesn't fit a simple map.\n",{"id":112,"difficulty":108,"q":113,"a":114},"reduce-grouping","How do you group array items by a key?","Use **reduce** to accumulate into buckets, initializing each bucket lazily.\n\n```js\nconst items = [{ type: 'a', v: 1 }, { type: 'b', v: 2 }, { type: 'a', v: 3 }]\nconst grouped = items.reduce((acc, item) => {\n  (acc[item.type] ??= []).push(item) \u002F\u002F create bucket then push\n  return acc\n}, {})\n\u002F\u002F { a: [{a,1},{a,3}], b: [{b,2}] }\n```\n\nModern engines also offer **Object.groupBy(items, item => item.type)**, which\ndoes exactly this without the boilerplate.\n",{"id":116,"difficulty":35,"q":117,"a":118},"reduce-flatten","How can reduce flatten an array of arrays?","Concatenate each sub-array into an accumulator:\n\n```js\nconst nested = [[1, 2], [3], [4, 5]]\nconst flat = nested.reduce((acc, sub) => acc.concat(sub), []) \u002F\u002F [1,2,3,4,5]\n```\n\nIn practice prefer the dedicated `nested.flat()` — it's clearer and faster. The\nreduce version is mostly useful as an interview demonstration of how flattening\nworks under the hood, or when you need custom merge logic per chunk.\n",{"id":120,"difficulty":43,"q":121,"a":122},"map-index","How do you access the index inside map, filter, or forEach?","Every iteration callback receives `(element, index, array)`. The second\nparameter is the index.\n\n```js\n['a', 'b', 'c'].map((char, i) => `${i}:${char}`) \u002F\u002F ['0:a', '1:b', '2:c']\n```\n\nGotcha: passing a method like `arr.map(parseInt)` breaks because `parseInt`\nreceives the index as its radix argument: `['1','2','3'].map(parseInt)` gives\n`[1, NaN, NaN]`. Wrap it: `arr.map(Number)` or `arr.map(s => parseInt(s, 10))`.\n",{"id":124,"difficulty":43,"q":125,"a":126},"map-vs-foreach","When should you choose map over forEach?","Choose **map** when you want a **transformed array** back; choose **forEach**\nwhen you only need **side effects** and ignore the return value.\n\n```js\nconst upper = names.map(n => n.toUpperCase()) \u002F\u002F need result\nnames.forEach(n => console.log(n))            \u002F\u002F side effect only\n```\n\nUsing `map` without consuming the result is a code smell — it implies a\ntransformation that's thrown away, confusing readers and wasting an allocation.\n",{"id":128,"difficulty":108,"q":129,"a":130},"chaining-vs-loop","What are the performance tradeoffs of chaining versus a single loop?","Each chained method (`filter().map()`) does a **full pass** and **allocates a\nnew array**. A single `for` loop or one `reduce` does one pass with no\nintermediate arrays.\n\n```js\n\u002F\u002F 2 passes, 2 arrays\narr.filter(x => x > 0).map(x => x * 2)\n\u002F\u002F 1 pass, 1 array\narr.reduce((acc, x) => (x > 0 && acc.push(x * 2), acc), [])\n```\n\nFor typical data sizes the difference is negligible and readability wins. Only\nfuse into a loop when profiling shows it matters.\n",{"id":132,"difficulty":43,"q":133,"a":134},"chaining-empty","What happens when you chain methods on an empty array?","Iteration methods on an empty array simply **don't call the callback** and\nreturn an empty (or seeded) result — no errors.\n\n```js\n[].map(x => x.boom)        \u002F\u002F [] — callback never runs\n[].filter(Boolean)         \u002F\u002F []\n[].reduce((a, b) => a + b) \u002F\u002F throws — no initial value\n```\n\nThe only landmine is `reduce` with no initial value, which throws on empty\ninput. Everything else degrades gracefully to an empty result.\n",{"id":136,"difficulty":35,"q":137,"a":138},"which-method","How do you decide which iteration method to use?","Match the method to the **shape of the result** you want:\n\n```text\ntransform each -> map\nkeep a subset -> filter\none value -> reduce\na single match -> find \u002F findIndex\nyes\u002Fno across all -> some \u002F every\nside effects only -> forEach (or for...of)\n```\n\nPicking the right method makes intent obvious. Reaching for `reduce` when\n`map` or `filter` fits is a common over-engineering mistake.\n",{"id":140,"difficulty":35,"q":141,"a":142},"chaining-readability","How can you keep long method chains readable?","Put **each step on its own line**, name intermediate results when a chain gets\nlong, and keep callbacks small (extract named functions for complex logic).\n\n```js\nconst activeNames = users\n  .filter(isActive)      \u002F\u002F named predicate\n  .map(u => u.name)\n  .sort(byAlpha)\n```\n\nA chain longer than 3-4 steps, or with multi-line callbacks, is often clearer\nsplit into named variables. Optimize for the next reader, not for fewer lines.\n",{"id":144,"difficulty":43,"q":145,"a":146},"copy-with-map","Does map produce a deep or shallow copy?","`map` produces a **new array**, but the elements are the **same references** for\nobjects — it's a **shallow** transform.\n\n```js\nconst arr = [{ n: 1 }]\nconst copy = arr.map(o => o)\ncopy[0].n = 99\narr[0].n \u002F\u002F 99 — same object reference\n```\n\nTo copy each object too, map to a new object: `arr.map(o => ({ ...o }))`. For\ndeeply nested data, `structuredClone` per element is safer.\n",{"id":148,"difficulty":108,"q":149,"a":150},"side-effects-in-map","Why are side effects inside map considered an anti-pattern?","`map` is meant to be a **pure transformation**: input array in, new array out.\nMutating external state or other elements inside the callback makes the code\nhard to reason about and order-dependent.\n\n```js\nlet total = 0\narr.map(x => { total += x; return x }) \u002F\u002F hidden side effect\n```\n\nUse `forEach`\u002F`for...of` for side effects and `reduce` for accumulation. Keep\n`map` pure so chains stay predictable and refactor-safe.\n",{"id":152,"difficulty":35,"q":153,"a":154},"chaining-find-after-filter","Why is filter().find() sometimes wasteful, and what's better?","`filter` walks the **entire array** building a new one, then `find` walks again.\nIf you only need the first match, `find` alone short-circuits on the first hit.\n\n```js\narr.filter(x => x > 10)[0]   \u002F\u002F full pass + array allocation\narr.find(x => x > 10)        \u002F\u002F stops at first match\n```\n\nSimilarly, prefer `some` over `filter(...).length > 0`. Choosing a\nshort-circuiting method avoids unnecessary work on large arrays.\n",{"id":156,"difficulty":35,"q":157,"a":158},"reduce-max","How do you find the maximum value with reduce?","Thread the running maximum through the accumulator:\n\n```js\nconst max = [3, 7, 2, 9, 4].reduce((m, n) => (n > m ? n : m), -Infinity)\n\u002F\u002F 9\n```\n\nSeeding with `-Infinity` keeps it correct even when all values are negative.\nFor plain numbers `Math.max(...arr)` is shorter, but it risks a stack overflow\non very large arrays — reduce stays safe there.\n",{"id":160,"difficulty":43,"q":161,"a":162},"array-isarray","How do you reliably check if a value is an array?","Use **Array.isArray**. `typeof []` returns `'object'`, so it can't distinguish\narrays from other objects.\n\n```js\nArray.isArray([1, 2]) \u002F\u002F true\nArray.isArray('ab')   \u002F\u002F false\ntypeof []             \u002F\u002F 'object' — useless here\n```\n\n`Array.isArray` also works correctly across **iframes\u002Frealms**, where\n`instanceof Array` can fail because each realm has its own `Array` constructor.\n",{"id":164,"difficulty":108,"q":165,"a":166},"foreach-async","Why does forEach not work well with async\u002Fawait?","`forEach` **ignores the promise** returned by an async callback, so it does not\nwait — the loop finishes before any async work completes.\n\n```js\nids.forEach(async id => { await save(id) }) \u002F\u002F doesn't await\n\u002F\u002F \"done\" logs before saves finish\n\nfor (const id of ids) { await save(id) }    \u002F\u002F sequential\nawait Promise.all(ids.map(id => save(id)))  \u002F\u002F parallel\n```\n\nUse a `for...of` loop for sequential awaits, or `map` + `Promise.all` to run\nthem concurrently and await the lot.\n",{"id":168,"difficulty":35,"q":169,"a":170},"callback-third-arg","What is the third argument passed to array iteration callbacks?","It's the **array being iterated** itself. It lets a callback reference\nneighboring elements without closing over an outer variable.\n\n```js\n[10, 20, 30].map((val, i, arr) =>\n  i > 0 ? val - arr[i - 1] : 0\n) \u002F\u002F [0, 10, 10] — differences\n```\n\nIt's rarely needed, but handy for look-ahead\u002Flook-behind logic and for writing\ngeneric helpers that don't depend on an external reference to the array.\n",null,{"description":32},"JavaScript array method interview questions — map, filter, reduce, forEach, some, every, find, flat, flatMap, Array.from and how to chain iteration methods effectively.","javascript\u002Farrays\u002Farray-methods","2026-06-18","Elw--T-gcVD4zuO2afQStkL-UYCKrtemiCrb2WELzjs",{"id":178,"title":179,"body":180,"description":32,"difficulty":35,"extension":36,"framework":10,"frameworkSlug":8,"meta":184,"navigation":38,"order":33,"path":185,"questions":186,"related":171,"seo":311,"seoDescription":312,"stem":313,"subtopic":314,"topic":19,"topicSlug":21,"updated":175,"__hash__":315},"qa\u002Fjavascript\u002Farrays\u002Fmutating-vs-nonmutating.md","Mutating Vs Nonmutating",{"type":29,"value":181,"toc":182},[],{"title":32,"searchDepth":33,"depth":33,"links":183},[],{},"\u002Fjavascript\u002Farrays\u002Fmutating-vs-nonmutating",[187,191,195,199,203,207,211,215,219,223,227,231,235,239,243,247,251,255,259,263,267,271,275,279,283,287,291,295,299,303,307],{"id":188,"difficulty":43,"q":189,"a":190},"what-is-mutation","What does it mean for an array method to mutate the array?","A **mutating** method changes the **original array in place** rather than\nreturning a fresh copy. The variable still points to the same array, but its\ncontents have changed.\n\n```js\nconst arr = [1, 2, 3]\narr.push(4) \u002F\u002F mutates: arr is now [1, 2, 3, 4]\n```\n\nThis matters because other code holding a reference to the same array sees the\nchange too — a frequent source of surprising bugs in shared state.\n",{"id":192,"difficulty":35,"q":193,"a":194},"list-mutating","Which array methods mutate the original array?","The classic mutators all change the array in place:\n\n```text\npush, pop, shift, unshift  -> add\u002Fremove ends\nsplice                     -> insert\u002Fremove\u002Freplace anywhere\nsort, reverse              -> reorder\nfill, copyWithin           -> overwrite ranges\n```\n\nA memory aid: if a method changes **length or order**, it almost certainly\nmutates. The notable surprise is that **sort** and **reverse** mutate — many\nassume they return a new array like `map`.\n",{"id":196,"difficulty":35,"q":197,"a":198},"list-nonmutating","Which common array methods return a new array instead of mutating?","These leave the original untouched and return a **new array**:\n\n```text\nmap, filter, slice, concat, flat, flatMap\ntoSorted, toReversed, toSpliced, with   (ES2023)\n```\n\nPlus the spread copy `[...arr]`. As a rule, the **iteration\u002Ftransform** methods\nare non-mutating, while the **in-place edit** methods mutate. Knowing which is\nwhich is essential for writing predictable code.\n",{"id":200,"difficulty":43,"q":201,"a":202},"push-vs-concat","What is the difference between push and concat?","**push** mutates the array and returns the **new length**; **concat** returns a\n**new array** and leaves the original alone.\n\n```js\nconst a = [1, 2]\na.push(3)        \u002F\u002F a is [1,2,3], returns 3\nconst b = a.concat(4) \u002F\u002F b is [1,2,3,4], a unchanged\n```\n\nPitfall: people sometimes write `arr = arr.push(x)`, which sets `arr` to a\nnumber (the length). Use `concat` or spread when you want a new array\nreference.\n",{"id":204,"difficulty":35,"q":205,"a":206},"slice-vs-splice","What is the difference between slice and splice?","**slice** is **non-mutating**: it returns a shallow copy of a range. **splice**\n**mutates**: it removes\u002Finserts elements in place and returns the removed ones.\n\n```js\nconst arr = [1, 2, 3, 4]\narr.slice(1, 3)     \u002F\u002F [2, 3], arr unchanged\narr.splice(1, 2)    \u002F\u002F removes [2, 3], arr is now [1, 4]\n```\n\nThe names look alike but behave oppositely on mutation. Confusing them is a\nclassic bug — remember **slice = copy, splice = surgery**.\n",{"id":208,"difficulty":35,"q":209,"a":210},"sort-mutates","Does sort mutate the array?","Yes. **sort** sorts the array **in place** and also returns a reference to that\n**same** array — so both the original and the return value are sorted.\n\n```js\nconst arr = [3, 1, 2]\nconst sorted = arr.sort()\nsorted === arr \u002F\u002F true — same array\narr            \u002F\u002F [1, 2, 3] — original is changed\n```\n\nTo sort without mutating, copy first (`[...arr].sort()`) or use **toSorted()**\nin modern environments. The same applies to `reverse`.\n",{"id":212,"difficulty":35,"q":213,"a":214},"tosorted","What is toSorted and how does it differ from sort?","**toSorted** (ES2023) returns a **new sorted array** and leaves the original\nunchanged — the immutable counterpart of `sort`.\n\n```js\nconst arr = [3, 1, 2]\nconst sorted = arr.toSorted() \u002F\u002F [1, 2, 3]\narr                           \u002F\u002F [3, 1, 2] — untouched\n```\n\nIt takes the same optional comparator as `sort`. Use it to avoid the classic\n`[...arr].sort()` copy dance, especially in React state where mutating is a\nbug.\n",{"id":216,"difficulty":35,"q":217,"a":218},"toreversed-tospliced-with","What do toReversed, toSpliced, and with do?","They are the **immutable** versions of `reverse`, `splice`, and index\nassignment, all returning a **new array** (ES2023).\n\n```js\nconst arr = [1, 2, 3]\narr.toReversed()       \u002F\u002F [3, 2, 1], arr unchanged\narr.toSpliced(1, 1, 9) \u002F\u002F [1, 9, 3], arr unchanged\narr.with(0, 100)       \u002F\u002F [100, 2, 3], arr unchanged\n```\n\n`with(i, value)` is the immutable replacement for `arr[i] = value`. Together\nthese let you write update logic without copying first.\n",{"id":220,"difficulty":108,"q":221,"a":222},"why-mutation-bugs","Why does mutation cause bugs in shared state?","When two variables reference the **same array**, mutating through one changes\nwhat the other sees. Functions that mutate their arguments cause **action at a\ndistance**.\n\n```js\nconst original = [1, 2, 3]\nconst sorted = original\nsorted.sort((a, b) => b - a)\noriginal \u002F\u002F [3, 2, 1] — caller's array got reordered\n```\n\nFrameworks like React rely on **referential equality** to detect changes;\nmutating in place keeps the same reference, so the UI may not re-render.\nReturning new arrays avoids both classes of bug.\n",{"id":224,"difficulty":43,"q":225,"a":226},"copy-array-ways","What are the ways to copy an array?","For a **shallow** copy, any of these work:\n\n```js\nconst a = [1, 2, 3]\nconst b = [...a]        \u002F\u002F spread (most common)\nconst c = a.slice()     \u002F\u002F no args = full copy\nconst d = Array.from(a) \u002F\u002F\nconst e = a.concat()    \u002F\u002F\n```\n\nAll four copy the top level only. If the array holds objects, the copies share\nthose objects — see deep copying for nested data.\n",{"id":228,"difficulty":35,"q":229,"a":230},"shallow-vs-deep","What is the difference between a shallow and a deep copy of an array?","A **shallow** copy duplicates the array but shares the **same nested object\nreferences**. A **deep** copy duplicates everything recursively.\n\n```js\nconst arr = [{ n: 1 }]\nconst shallow = [...arr]\nshallow[0].n = 99\narr[0].n \u002F\u002F 99 — nested object is shared\n\nconst deep = structuredClone(arr)\ndeep[0].n = 1\narr[0].n \u002F\u002F 99 — independent\n```\n\nSpread\u002Fslice are shallow; reach for `structuredClone` when nested data must be\nindependent.\n",{"id":232,"difficulty":35,"q":233,"a":234},"structuredclone","When and how do you use structuredClone for arrays?","**structuredClone** does a true **deep copy** of arrays containing nested\nobjects, arrays, Maps, Sets, Dates, and more — without the limitations of\nJSON tricks.\n\n```js\nconst data = [{ id: 1, tags: ['a'] }]\nconst copy = structuredClone(data) \u002F\u002F fully independent\n```\n\nCaveat: it **cannot clone functions, DOM nodes, or class instances** with\nmethods (it throws or drops the prototype). It's built into modern Node and all\ncurrent browsers.\n",{"id":236,"difficulty":35,"q":237,"a":238},"json-deep-copy","What are the pitfalls of JSON.parse(JSON.stringify(arr)) for deep copy?","It deep-copies plain data but **silently corrupts** anything non-JSON:\n\n```js\nconst arr = [{ d: new Date(), fn: () => {}, u: undefined, n: NaN }]\nJSON.parse(JSON.stringify(arr))\n\u002F\u002F Date -> string, fn -> dropped, undefined -> dropped, NaN -> null\n```\n\nIt also throws on **circular references**. Prefer `structuredClone` for deep\ncopies; reserve the JSON trick for arrays of plain, JSON-safe values where the\nconversions don't matter.\n",{"id":240,"difficulty":35,"q":241,"a":242},"immutable-add","How do you add an item to an array immutably?","Build a **new array** with spread instead of `push`\u002F`unshift`:\n\n```js\nconst arr = [1, 2, 3]\nconst appended = [...arr, 4]   \u002F\u002F add to end\nconst prepended = [0, ...arr]  \u002F\u002F add to start\narr \u002F\u002F [1, 2, 3] — unchanged\n```\n\nThis pattern is standard in Redux reducers and React `setState`, where mutating\nthe existing array would break change detection and time-travel debugging.\n",{"id":244,"difficulty":35,"q":245,"a":246},"immutable-remove","How do you remove an item from an array immutably?","Use **filter** (by value\u002Fpredicate) or **slice + spread** (by index) to produce\na new array.\n\n```js\nconst arr = [1, 2, 3, 4]\narr.filter(n => n !== 3)             \u002F\u002F [1, 2, 4] by value\nconst i = 2\n[...arr.slice(0, i), ...arr.slice(i + 1)] \u002F\u002F [1, 2, 4] by index\narr.toSpliced(i, 1)                  \u002F\u002F [1, 2, 4] ES2023\n```\n\nAvoid `splice`, which mutates. `toSpliced` is the cleanest modern option for\nindex-based removal.\n",{"id":248,"difficulty":35,"q":249,"a":250},"immutable-update","How do you update an item at an index immutably?","Use **map** with the index, or **with()** in modern environments — never\n`arr[i] = x`, which mutates.\n\n```js\nconst arr = [1, 2, 3]\narr.map((v, idx) => (idx === 1 ? 99 : v)) \u002F\u002F [1, 99, 3]\narr.with(1, 99)                            \u002F\u002F [1, 99, 3] ES2023\narr \u002F\u002F [1, 2, 3] — unchanged\n```\n\nFor arrays of objects, also spread the object: `arr.map(o => o.id === id ? {\n...o, done: true } : o)` to avoid mutating the nested object.\n",{"id":252,"difficulty":108,"q":253,"a":254},"freeze-array","Does Object.freeze make an array fully immutable?","It makes it **shallowly** immutable: you can't add, remove, or reassign\ntop-level elements, but **nested objects stay mutable**.\n\n```js\nconst arr = Object.freeze([{ n: 1 }])\narr.push(2)   \u002F\u002F throws in strict mode (or silently fails)\narr[0].n = 99 \u002F\u002F still works — nested object not frozen\n```\n\nFor deep immutability you must freeze recursively (a \"deep freeze\"). Also note\nmutating methods like `push` throw on a frozen array in strict mode.\n",{"id":256,"difficulty":35,"q":257,"a":258},"fill","What does fill do and does it mutate?","**fill** overwrites a range of the array with a static value **in place** — it\nmutates and returns the same array.\n\n```js\nconst arr = [1, 2, 3, 4]\narr.fill(0, 1, 3) \u002F\u002F [1, 0, 0, 4], arr mutated\nnew Array(3).fill(0) \u002F\u002F [0, 0, 0] — common init pattern\n```\n\nGotcha: filling with a **shared object** puts the **same reference** in every\nslot: `new Array(3).fill([])` gives three references to one array. Use\n`Array.from({length:3}, () => [])` for distinct objects.\n",{"id":260,"difficulty":108,"q":261,"a":262},"copywithin","What does copyWithin do?","**copyWithin(target, start, end)** copies a slice of the array to another\nposition **within the same array**, in place, without changing its length.\n\n```js\nconst arr = [1, 2, 3, 4, 5]\narr.copyWithin(0, 3) \u002F\u002F [4, 5, 3, 4, 5] — copy from index 3 to 0\n```\n\nIt mutates and is rarely used in app code — it exists mainly for high\nperformance buffer manipulation. Worth recognizing in interviews but seldom\nreached for in practice.\n",{"id":264,"difficulty":43,"q":265,"a":266},"reverse-mutates","Does reverse mutate the array?","Yes — **reverse** reverses the array **in place** and returns a reference to the\nsame array.\n\n```js\nconst arr = [1, 2, 3]\narr.reverse()\narr \u002F\u002F [3, 2, 1] — original changed\n```\n\nTo reverse without mutating, use `[...arr].reverse()` or **toReversed()**. This\nmutation surprises people who expect array methods to be functional like `map`.\n",{"id":268,"difficulty":43,"q":269,"a":270},"assignment-not-copy","Why doesn't const b = a create a copy of the array?","Arrays are **reference types**. Assignment copies the **reference**, not the\ndata, so both names point at the **same array**.\n\n```js\nconst a = [1, 2, 3]\nconst b = a\nb.push(4)\na \u002F\u002F [1, 2, 3, 4] — same array\n```\n\nTo get an independent array you must explicitly copy: `const b = [...a]`. This\nreference behavior underlies most accidental-mutation bugs.\n",{"id":272,"difficulty":35,"q":273,"a":274},"mutation-in-functions","How can passing an array to a function mutate the caller's array?","The function receives the **same reference**, so any mutating method affects the\ncaller's array.\n\n```js\nfunction addItem(arr) { arr.push('x') } \u002F\u002F mutates caller\nconst list = [1]\naddItem(list)\nlist \u002F\u002F [1, 'x']\n```\n\nWrite **pure** functions that return new arrays instead: `function addItem(arr)\n{ return [...arr, 'x'] }`. This keeps call sites free of surprises and makes the\ncode easier to test.\n",{"id":276,"difficulty":35,"q":277,"a":278},"spread-shallow","Is the spread operator a deep or shallow copy for arrays?","**Shallow.** Spread copies the top-level elements; nested objects\u002Farrays are\nstill **shared by reference**.\n\n```js\nconst arr = [[1], [2]]\nconst copy = [...arr]\ncopy[0].push(99)\narr[0] \u002F\u002F [1, 99] — inner array shared\n```\n\nFor nested data you need a deep copy (`structuredClone`) or to spread each\nlevel. Treat spread as a fast top-level clone, nothing more.\n",{"id":280,"difficulty":108,"q":281,"a":282},"react-mutation","Why must you avoid mutating arrays in React state?","React decides whether to re-render by comparing the **previous and next\nreference**. Mutating in place keeps the **same reference**, so React thinks\nnothing changed.\n\n```js\n\u002F\u002F mutation — same reference, no re-render\nitems.push(newItem); setItems(items)\n\u002F\u002F new reference — triggers re-render\nsetItems([...items, newItem])\n```\n\nAlways create a new array (`map`, `filter`, spread, `toSorted`, `with`) when\nupdating state so React sees the change.\n",{"id":284,"difficulty":35,"q":285,"a":286},"empty-array-length","How does setting arr.length mutate the array?","Assigning to **length** mutates in place: shrinking truncates elements,\ngrowing pads with empty slots, and `length = 0` empties the array.\n\n```js\nconst arr = [1, 2, 3, 4]\narr.length = 2 \u002F\u002F [1, 2] — truncated\narr.length = 0 \u002F\u002F [] — cleared\n```\n\n`arr.length = 0` is a fast in-place clear that affects every reference to the\narray. To clear without mutating shared references, reassign: `arr = []`.\n",{"id":288,"difficulty":43,"q":289,"a":290},"pop-shift-return","What do pop and shift return, and do they mutate?","Both **mutate** and return the **removed element**. `pop` removes from the end,\n`shift` from the start.\n\n```js\nconst arr = [1, 2, 3]\narr.pop()   \u002F\u002F returns 3, arr is [1, 2]\narr.shift() \u002F\u002F returns 1, arr is [2]\n```\n\nNote `shift`\u002F`unshift` are **O(n)** because every remaining element must be\nreindexed, whereas `push`\u002F`pop` are O(1). Prefer end operations in hot loops.\n",{"id":292,"difficulty":43,"q":293,"a":294},"concat-vs-spread","Are concat and spread interchangeable for combining arrays?","Mostly yes — both return a **new array** without mutating. Spread reads more\nnaturally; `concat` has one nicety: it accepts **non-array values** directly.\n\n```js\n[...a, ...b]      \u002F\u002F merge two arrays\na.concat(b)       \u002F\u002F same result\na.concat(b, 5, 6) \u002F\u002F concat flattens array args and appends values\n[...a, b]         \u002F\u002F pushes the array b as a single element\n```\n\nFor huge arrays `concat` can be marginally faster, but readability usually\nfavors spread.\n",{"id":296,"difficulty":108,"q":297,"a":298},"in-place-dedupe","How do you dedupe an array, mutating versus non-mutating?","The clean, **non-mutating** way uses a `Set`:\n\n```js\nconst unique = [...new Set(arr)] \u002F\u002F new array, order preserved\n```\n\nAn in-place dedupe is fiddly and error-prone (you'd `splice` while iterating,\nwhich shifts indices). Prefer the Set approach. Note it uses **SameValueZero**,\nso `NaN` is deduped correctly but distinct objects with equal contents are not.\n",{"id":300,"difficulty":35,"q":301,"a":302},"immutability-libraries","What problem do libraries like Immer solve for arrays?","They let you write **mutating-looking** code that actually produces a **new,\nimmutable** array under the hood, avoiding verbose spread chains for deeply\nnested updates.\n\n```js\nconst next = produce(state, draft => {\n  draft.items.push(newItem) \u002F\u002F looks like mutation\n}) \u002F\u002F state is untouched, next is a new tree\n```\n\nImmer tracks changes to a proxy \"draft\" and builds the new structure for you.\nIt's popular in Redux Toolkit precisely because deep immutable updates with\nspread get unwieldy.\n",{"id":304,"difficulty":108,"q":305,"a":306},"detect-mutation","How can you guard against accidental mutation during development?","Use **Object.freeze** in development to make accidental mutation throw, lean on\n**const** (which prevents reassignment, not mutation), and adopt lint rules or\nlibraries that enforce immutability.\n\n```js\nconst config = Object.freeze([1, 2, 3])\nconfig.push(4) \u002F\u002F throws in strict mode — caught early\n```\n\nIn TypeScript, `readonly` arrays and `as const` give **compile-time**\nprotection with zero runtime cost, catching mutation before it ships.\n",{"id":308,"difficulty":35,"q":309,"a":310},"prefer-immutable","When should you prefer immutable updates over mutation?","Prefer **immutable** updates whenever the array is **shared** — across\ncomponents, stored in framework state, or passed between modules — because new\nreferences make change tracking and reasoning reliable.\n\n```js\n\u002F\u002F shared state -> immutable\nsetItems(items.filter(i => i.id !== id)) \u002F\u002F\n```\n\n**Mutation is fine** for short-lived local arrays you fully own inside a\nfunction, where in-place edits are faster and no one else can observe them.\n",{"description":32},"JavaScript array mutation interview questions — which methods mutate versus return a new array, immutability patterns, copying arrays, the new toSorted and with methods, and structuredClone for nested data.","javascript\u002Farrays\u002Fmutating-vs-nonmutating","Mutating vs Non-Mutating","54QuTuRi8ysB-Ri5IyNJ6VfxTJXeWyfqI2yjBC5sMQg",{"id":317,"title":318,"body":319,"description":32,"difficulty":35,"extension":36,"framework":10,"frameworkSlug":8,"meta":323,"navigation":38,"order":324,"path":325,"questions":326,"related":171,"seo":447,"seoDescription":448,"stem":449,"subtopic":450,"topic":19,"topicSlug":21,"updated":175,"__hash__":451},"qa\u002Fjavascript\u002Farrays\u002Fsearching-sorting.md","Searching Sorting",{"type":29,"value":320,"toc":321},[],{"title":32,"searchDepth":33,"depth":33,"links":322},[],{},3,"\u002Fjavascript\u002Farrays\u002Fsearching-sorting",[327,331,335,339,343,347,351,353,357,361,365,368,372,376,380,384,388,391,395,399,403,407,411,415,419,423,427,431,435,439,443],{"id":328,"difficulty":43,"q":329,"a":330},"indexof-basics","How does indexOf work and what does it return when nothing is found?","**`indexOf`** returns the index of the first element strictly equal\n(`===`) to the search value, or **`-1`** if it is not present.\n\n```js\nconst a = ['x', 'y', 'z']\na.indexOf('y')   \u002F\u002F 1\na.indexOf('q')   \u002F\u002F -1  the \"not found\" sentinel\n```\n\nThe classic pitfall is treating `-1` as falsy: `if (a.indexOf(x))` is\n**wrong** because index `0` is also falsy. Compare explicitly with\n`!== -1`, or prefer `includes` when you only need a boolean.\n",{"id":332,"difficulty":43,"q":333,"a":334},"lastindexof","What is the difference between indexOf and lastIndexOf?","**`indexOf`** searches front-to-back and returns the first match;\n**`lastIndexOf`** searches back-to-front and returns the last match.\nBoth use `===` and return `-1` when absent.\n\n```js\nconst a = [1, 2, 3, 2, 1]\na.indexOf(2)      \u002F\u002F 1\na.lastIndexOf(2)  \u002F\u002F 3  last occurrence\n```\n\nEach also takes an optional start index. A subtle point: for\n`lastIndexOf` the second argument is where to *begin searching\nbackwards*, so `a.lastIndexOf(2, 2)` searches indices 2->0.\n",{"id":336,"difficulty":35,"q":337,"a":338},"includes-vs-indexof","When should you use includes instead of indexOf?","Use **`includes`** when you only care *whether* a value exists — it\nreturns a boolean and reads clearly. Use **`indexOf`** when you need the\n*position*.\n\n```js\nif (tags.includes('urgent')) { \u002F* ... *\u002F }   \u002F\u002F clear intent\nconst at = tags.indexOf('urgent')            \u002F\u002F when you need where\n```\n\nThe other reason to prefer `includes`: it finds `NaN`, which `indexOf`\ncannot (see the next question).\n",{"id":340,"difficulty":35,"q":341,"a":342},"nan-search-gotcha","Why can't indexOf find NaN, but includes can?","`indexOf` compares with `===`, and `NaN === NaN` is **false** — so it can\nnever match. `includes` uses the **SameValueZero** algorithm, which\ntreats `NaN` as equal to `NaN`.\n\n```js\n[NaN].indexOf(NaN)    \u002F\u002F -1  can't find it\n[NaN].includes(NaN)   \u002F\u002F true\n```\n\nSameValueZero is also why `includes(0)` matches both `+0` and `-0`. If\nyou must locate a `NaN` index, use `findIndex(Number.isNaN)`.\n",{"id":344,"difficulty":43,"q":345,"a":346},"find-vs-filter","What is the difference between find and filter?","**`find`** returns the **first element** that satisfies the predicate (or\n`undefined`); **`filter`** returns a **new array** of *all* matches.\n\n```js\nusers.find(u => u.id === 7)     \u002F\u002F the one user, or undefined\nusers.filter(u => u.active)     \u002F\u002F array of every active user\n```\n\nUse `find` for \"give me the one I want\" — it also short-circuits on the\nfirst match, so it's cheaper than `filter()[0]` which scans the whole\narray.\n",{"id":348,"difficulty":43,"q":349,"a":350},"findindex","When would you use findIndex over indexOf?","**`indexOf`** searches by value equality; **`findIndex`** searches by a\n**predicate function**, so it works for objects and complex conditions.\n\n```js\nconst i = users.indexOf(someUser)          \u002F\u002F needs the exact reference\nconst j = users.findIndex(u => u.id === 7) \u002F\u002F search by a property\n```\n\nBoth return `-1` when nothing matches. Reach for `findIndex` whenever the\nmatch is \"the element where some condition holds\" rather than \"this exact\nvalue.\"\n",{"id":75,"difficulty":35,"q":76,"a":352},"They are the back-to-front counterparts of `find`\u002F`findIndex`: they walk\nthe array **from the end** and return the first matching element \u002F index.\n\n```js\nconst nums = [1, 8, 3, 9, 2]\nnums.findLast(n => n > 4)       \u002F\u002F 9  last match, not first\nnums.findLastIndex(n => n > 4)  \u002F\u002F 3\n```\n\nBefore these (ES2023) you'd reverse a copy or loop manually. They're handy\nfor \"most recent\" lookups in append-ordered data like logs.\n",{"id":354,"difficulty":43,"q":355,"a":356},"some-every-search","How do some and every help with searching?","**`some`** answers \"does *any* element match?\" and **`every`** answers\n\"do *all* elements match?\" — both return a boolean and short-circuit.\n\n```js\nnums.some(n => n \u003C 0)    \u002F\u002F true if there's at least one negative\nnums.every(n => n > 0)   \u002F\u002F true only if all are positive\n```\n\n`some` stops at the first `true`; `every` stops at the first `false`. A\ngotcha: `every` on an **empty array is `true`** (vacuous truth) and `some`\non an empty array is `false`.\n",{"id":358,"difficulty":35,"q":359,"a":360},"sort-default-gotcha","Why does sorting numbers with sort() give wrong results?","Without a comparator, **`sort` converts elements to strings** and compares\nthem by UTF-16 code unit — so numbers sort lexicographically.\n\n```js\n[10, 1, 2, 20].sort()            \u002F\u002F [1, 10, 2, 20]  \"10\" \u003C \"2\"\n[10, 1, 2, 20].sort((a,b)=>a-b)  \u002F\u002F [1, 2, 10, 20]\n```\n\nAlways pass a comparator for numbers. This string-coercion default trips\nup nearly everyone at least once.\n",{"id":362,"difficulty":43,"q":363,"a":364},"numeric-comparator","How do you write an ascending and descending numeric comparator?","A comparator returns a **negative** number if `a` should come first, a\n**positive** number if `b` should, and `0` to leave order unchanged.\n\n```js\narr.sort((a, b) => a - b)   \u002F\u002F ascending\narr.sort((a, b) => b - a)   \u002F\u002F descending\n```\n\nThe `a - b` trick works only for numbers. Don't return a boolean\n(`a > b`) — coerced to `0`\u002F`1` it never yields a negative, so the sort is\nbroken.\n",{"id":208,"difficulty":35,"q":366,"a":367},"Does sort() mutate the array? How do you sort without mutating?","Yes — **`sort` sorts in place and returns the same array reference**.\nThat can surprise callers sharing the array.\n\n```js\nconst a = [3, 1, 2]\nconst b = a.sort((x,y)=>x-y)\nb === a            \u002F\u002F true  original mutated\n\nconst sorted = [...a].sort((x,y)=>x-y)  \u002F\u002F copy first\nconst safe = a.toSorted((x,y)=>x-y)     \u002F\u002F ES2023, returns new array\n```\n\nPrefer `toSorted` (or spread-then-sort) in code that values immutability,\ne.g. React state.\n",{"id":369,"difficulty":108,"q":370,"a":371},"stable-sort","Is JavaScript's sort stable, and why does that matter?","Since ES2019 `sort` is guaranteed **stable**: elements the comparator\ntreats as equal keep their original relative order. This makes\n**multi-pass sorting** reliable.\n\n```js\n\u002F\u002F sort by name, then by age — age becomes the primary key,\n\u002F\u002F ties broken by the earlier name order\npeople.sort((a,b)=>a.name.localeCompare(b.name))\n      .sort((a,b)=>a.age - b.age)  \u002F\u002F stable keeps name order within an age\n```\n\nBefore ES2019, engines like V8 used an unstable sort for large arrays, so\nthis pattern wasn't portable.\n",{"id":373,"difficulty":35,"q":374,"a":375},"sort-objects","How do you sort an array of objects by a property?","Compare the property inside the comparator. Subtract for numbers, use\n`localeCompare` for strings.\n\n```js\nusers.sort((a, b) => a.age - b.age)              \u002F\u002F numeric field\nusers.sort((a, b) => a.name.localeCompare(b.name)) \u002F\u002F string field\n```\n\nDon't use `a.name > b.name` directly — it returns a boolean and breaks the\ncomparator contract. Remember it mutates, so copy first if needed.\n",{"id":377,"difficulty":108,"q":378,"a":379},"multi-key-sort","How do you sort by multiple keys?","Evaluate keys in priority order and return the first non-zero comparison.\n\n```js\npeople.sort((a, b) =>\n  a.lastName.localeCompare(b.lastName) ||  \u002F\u002F primary\n  a.firstName.localeCompare(b.firstName) || \u002F\u002F tiebreaker\n  a.age - b.age                             \u002F\u002F final tiebreaker\n)\n```\n\nThe `||` chain works because a `0` (equal) is falsy, so it falls through\nto the next key. Clean and avoids nested `if`s.\n",{"id":381,"difficulty":35,"q":382,"a":383},"localecompare","Why use localeCompare for sorting strings?","Comparing strings with `\u003C`\u002F`>` uses raw UTF-16 code units, which mishandles\naccents and locale rules. **`localeCompare`** sorts the way humans expect\nfor a given language.\n\n```js\n['é', 'a', 'z'].sort()                       \u002F\u002F ['a', 'z', 'é']\n['é', 'a', 'z'].sort((a,b)=>a.localeCompare(b)) \u002F\u002F ['a', 'é', 'z']\n```\n\nFor large arrays, build a reusable `Intl.Collator` and pass its `compare`\nmethod — it's much faster than calling `localeCompare` repeatedly.\n",{"id":385,"difficulty":35,"q":386,"a":387},"case-insensitive-sort","How do you sort strings case-insensitively?","Either lowercase both sides, or use `localeCompare` with the\n`sensitivity: 'base'` option (which also ignores accents).\n\n```js\narr.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))\n\u002F\u002F or\narr.sort((a, b) =>\n  a.localeCompare(b, undefined, { sensitivity: 'base' }))  \u002F\u002F\n```\n\nThe `Intl` option is preferable: lowercasing can be wrong for some\nlanguages (e.g. Turkish dotless İ).\n",{"id":264,"difficulty":43,"q":389,"a":390},"Does reverse() mutate, and what's the immutable alternative?","Yes — **`reverse` reverses in place** and returns the same array. The\nES2023 immutable version is **`toReversed`**.\n\n```js\nconst a = [1, 2, 3]\na.reverse()        \u002F\u002F a is now [3, 2, 1]  mutated\nconst b = a.toReversed()  \u002F\u002F new array, a untouched\n```\n\nTo reverse-sort numbers, you don't need `reverse` at all — just flip the\ncomparator: `sort((x,y)=>y-x)`.\n",{"id":392,"difficulty":35,"q":393,"a":394},"indexof-fromindex","How does the second argument to indexOf and includes work?","It's the **start index**. Searching begins there and continues to the end.\nNegative values count from the end.\n\n```js\nconst a = ['a', 'b', 'a', 'b']\na.indexOf('a', 1)    \u002F\u002F 2  (skips index 0)\na.includes('a', -1)  \u002F\u002F false (only looks at last element)\n```\n\nUseful for finding *all* occurrences in a loop: keep calling\n`indexOf(x, lastFound + 1)` until it returns `-1`.\n",{"id":396,"difficulty":108,"q":397,"a":398},"find-all-indices","How do you find all indices where a condition holds?","There's no built-in, but `reduce` collects them in one pass, or `map` +\n`filter`.\n\n```js\nconst evens = nums.reduce((acc, n, i) => {\n  if (n % 2 === 0) acc.push(i)\n  return acc\n}, [])  \u002F\u002F array of indices\n```\n\nAvoid the naive `nums.map((n,i)=> n%2===0 ? i : -1).filter(i=>i!==-1)` —\nit's two passes and the `-1` sentinel is fragile if `0` is a valid index.\n",{"id":400,"difficulty":108,"q":401,"a":402},"binary-search","When is a manual binary search worthwhile over includes\u002FindexOf?","`includes`\u002F`indexOf` are **O(n)** linear scans. If the array is **already\nsorted** and you search it many times, a **binary search** is O(log n).\n\n```js\nfunction bsearch(arr, target) {\n  let lo = 0, hi = arr.length - 1\n  while (lo \u003C= hi) {\n    const mid = (lo + hi) >> 1\n    if (arr[mid] === target) return mid\n    arr[mid] \u003C target ? (lo = mid + 1) : (hi = mid - 1)\n  }\n  return -1\n}\n```\n\nThe pitfall: the array **must** stay sorted, and `(lo+hi)>>1` assumes\nindices small enough to avoid overflow (fine in practice for arrays).\n",{"id":404,"difficulty":108,"q":405,"a":406},"sort-numbers-strings-mix","What happens if you sort an array with mixed types?","The default sort stringifies everything, giving surprising order; a numeric\ncomparator on mixed types produces `NaN` comparisons that leave order\neffectively undefined.\n\n```js\n[3, '1', 2].sort()              \u002F\u002F ['1', 2, 3] — all compared as strings\n[3, 'x', 2].sort((a,b)=>a-b)    \u002F\u002F 'x'-num is NaN, order unreliable\n```\n\nNormalize types before sorting (e.g. `Number(x)`), or filter out invalid\nentries first. Mixed-type arrays are usually a data-modeling smell.\n",{"id":408,"difficulty":108,"q":409,"a":410},"sort-undefined","How does sort handle undefined and holes?","`sort` moves all **`undefined`** values to the **end** without calling the\ncomparator on them, and **holes** in sparse arrays go after even those.\n\n```js\n[3, undefined, 1].sort((a,b)=>a-b)  \u002F\u002F [1, 3, undefined]\n```\n\nSo you can't reliably place `undefined` via a comparator — the engine\nhandles them specially. Strip or default them beforehand if you need\nspecific placement.\n",{"id":412,"difficulty":35,"q":413,"a":414},"includes-object-reference","Why does includes return false for an object that \"looks\" the same?","`includes` uses identity (SameValueZero), so two distinct objects with the\nsame contents are **not** equal.\n\n```js\nconst arr = [{ id: 1 }]\narr.includes({ id: 1 })           \u002F\u002F false different reference\narr.some(o => o.id === 1)         \u002F\u002F true  compare by value\n```\n\nFor \"contains an object like this,\" use `some`\u002F`find` with a predicate, not\n`includes`\u002F`indexOf`.\n",{"id":416,"difficulty":35,"q":417,"a":418},"tosorted-toreversed","What are toSorted, toReversed, toSpliced, and with?","They are ES2023 **non-mutating** versions of `sort`, `reverse`, `splice`,\nand bracket assignment — each returns a **new array**.\n\n```js\na.toSorted((x,y)=>x-y)   \u002F\u002F sorted copy\na.toReversed()           \u002F\u002F reversed copy\na.toSpliced(1, 2)        \u002F\u002F copy with items removed\u002Finserted\na.with(0, 'new')         \u002F\u002F copy with index 0 replaced\n```\n\nThey make immutable updates concise — especially `with`, which replaces the\nold `[...a.slice(0,i), val, ...a.slice(i+1)]` dance.\n",{"id":420,"difficulty":35,"q":421,"a":422},"search-performance","When should you use a Set or Map instead of array searching?","Repeated `includes`\u002F`indexOf` lookups are **O(n)** each — O(n·m) overall.\nA **`Set`** gives O(1) membership tests.\n\n```js\nconst seen = new Set(bigArray)\nqueries.filter(q => seen.has(q))   \u002F\u002F O(1) per lookup\n```\n\nRule of thumb: if you search the same collection more than a handful of\ntimes, build a `Set`\u002F`Map` index once and query that instead.\n",{"id":424,"difficulty":35,"q":425,"a":426},"dedupe-sorted","How do you remove duplicates, optionally keeping order?","A **`Set`** dedupes and preserves first-seen insertion order in one line.\n\n```js\nconst unique = [...new Set(arr)]   \u002F\u002F order preserved\n```\n\nFor objects (reference equality won't help), dedupe by a key with a `Map`:\n\n```js\nconst byId = [...new Map(users.map(u => [u.id, u])).values()]\n```\n",{"id":428,"difficulty":108,"q":429,"a":430},"sort-comparator-cost","Why can repeated work inside a comparator be a performance problem?","The comparator runs **O(n log n)** times, so any expensive computation\ninside it is repeated constantly. Precompute keys once with a\n**Schwartzian transform**.\n\n```js\nconst sorted = items\n  .map(x => ({ x, key: expensiveKey(x) }))  \u002F\u002F compute once\n  .sort((a, b) => a.key - b.key)\n  .map(o => o.x)                              \u002F\u002F unwrap\n```\n\nThis trades a little memory for far fewer key computations than calling\n`expensiveKey` inside `sort`.\n",{"id":432,"difficulty":43,"q":433,"a":434},"find-default","What does find return when nothing matches, and why be careful?","It returns **`undefined`**. Destructuring or accessing properties on the\nresult without a guard then throws.\n\n```js\nconst u = users.find(u => u.id === 99)\nu.name              \u002F\u002F TypeError if not found\nu?.name             \u002F\u002F optional chaining\nconst { name } = u ?? {}  \u002F\u002F safe default\n```\n\nAlways treat `find`'s result as possibly `undefined`.\n",{"id":436,"difficulty":43,"q":437,"a":438},"indexof-vs-search-string","Does array indexOf relate to string indexOf?","They share a name and a `-1`-on-miss convention, but operate on different\nthings. **Array** `indexOf` matches an element by `===`; **string**\n`indexOf` finds a **substring**.\n\n```js\n['ab', 'cd'].indexOf('b')   \u002F\u002F -1  (no element equals 'b')\n'abcd'.indexOf('b')         \u002F\u002F 1   (substring position)\n```\n\nDon't expect array `indexOf` to do partial\u002Fsubstring matching — use\n`some(s => s.includes('b'))` for that.\n",{"id":440,"difficulty":108,"q":441,"a":442},"sort-locale-numeric","How do you sort strings that contain numbers \"naturally\" (file2 \u003C file10)?","Default and `localeCompare` without options give `file10 \u003C file2`\n(lexicographic). Pass `{ numeric: true }` for **natural sort**.\n\n```js\n['file10','file2'].sort()  \u002F\u002F ['file10','file2']\n['file10','file2'].sort((a,b)=>\n  a.localeCompare(b, undefined, { numeric: true }))\n\u002F\u002F ['file2','file10']\n```\n\nCombine with `sensitivity: 'base'` for case\u002Faccent-insensitive natural\nordering of filenames and version strings.\n",{"id":444,"difficulty":43,"q":445,"a":446},"empty-array-search","What do searching methods return on an empty array?","Consistent, safe defaults: `indexOf`\u002F`findIndex` return `-1`,\n`find` returns `undefined`, `includes`\u002F`some` return `false`, and\n`every` returns `true`.\n\n```js\n[].indexOf('x')   \u002F\u002F -1\n[].find(Boolean)  \u002F\u002F undefined\n[].some(Boolean)  \u002F\u002F false\n[].every(Boolean) \u002F\u002F true   vacuously\n```\n\nThe `every === true` on empty is the one that surprises people in\nvalidation logic — guard for emptiness if \"all valid\" shouldn't pass on no\ndata.\n",{"description":32},"JavaScript array searching and sorting interview questions — indexOf, includes, find, the sort() coercion gotcha, numeric comparators, stable sort, toSorted and sorting objects.","javascript\u002Farrays\u002Fsearching-sorting","Searching & Sorting","rwKZ3UXQprDpLSR117P9VFRLTkhBfPapY8I3dIMex0Q",{"id":453,"title":454,"body":455,"description":32,"difficulty":35,"extension":36,"framework":10,"frameworkSlug":8,"meta":459,"navigation":38,"order":460,"path":461,"questions":462,"related":171,"seo":587,"seoDescription":588,"stem":589,"subtopic":590,"topic":19,"topicSlug":21,"updated":175,"__hash__":591},"qa\u002Fjavascript\u002Farrays\u002Fdestructuring-spread.md","Destructuring Spread",{"type":29,"value":456,"toc":457},[],{"title":32,"searchDepth":33,"depth":33,"links":458},[],{},4,"\u002Fjavascript\u002Farrays\u002Fdestructuring-spread",[463,467,471,475,479,483,487,491,495,499,503,507,511,515,519,523,527,531,535,539,543,547,551,555,559,563,567,571,575,579,583],{"id":464,"difficulty":43,"q":465,"a":466},"array-destructuring-basics","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":468,"difficulty":43,"q":469,"a":470},"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":472,"difficulty":43,"q":473,"a":474},"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":476,"difficulty":43,"q":477,"a":478},"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":480,"difficulty":35,"q":481,"a":482},"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":484,"difficulty":35,"q":485,"a":486},"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":488,"difficulty":35,"q":489,"a":490},"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":492,"difficulty":43,"q":493,"a":494},"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":496,"difficulty":43,"q":497,"a":498},"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":500,"difficulty":35,"q":501,"a":502},"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":504,"difficulty":35,"q":505,"a":506},"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":508,"difficulty":35,"q":509,"a":510},"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":512,"difficulty":43,"q":513,"a":514},"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":516,"difficulty":35,"q":517,"a":518},"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":520,"difficulty":35,"q":521,"a":522},"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":524,"difficulty":35,"q":525,"a":526},"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":528,"difficulty":35,"q":529,"a":530},"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":532,"difficulty":108,"q":533,"a":534},"default-from-other","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":536,"difficulty":35,"q":537,"a":538},"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":540,"difficulty":108,"q":541,"a":542},"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":544,"difficulty":35,"q":545,"a":546},"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":548,"difficulty":35,"q":549,"a":550},"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":552,"difficulty":35,"q":553,"a":554},"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":556,"difficulty":108,"q":557,"a":558},"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":560,"difficulty":43,"q":561,"a":562},"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":564,"difficulty":43,"q":565,"a":566},"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":568,"difficulty":35,"q":569,"a":570},"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":572,"difficulty":43,"q":573,"a":574},"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":576,"difficulty":43,"q":577,"a":578},"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":580,"difficulty":108,"q":581,"a":582},"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":584,"difficulty":108,"q":585,"a":586},"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",{"description":32},"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","dwUK35g8bIJziTXcSu72Y0e_b_MJftZi1sERh1noiQ0",1781808674571]