[{"data":1,"prerenderedAt":177},["ShallowReactive",2],{"qa-\u002Fjavascript\u002Farrays\u002Farray-methods":3},{"page":4,"siblings":161,"blog":174},{"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":153,"seo":154,"seoDescription":155,"stem":156,"subtopic":6,"topic":157,"topicSlug":158,"updated":159,"__hash__":160},"qa\u002Fjavascript\u002Farrays\u002Farray-methods.md","Array Methods",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","JavaScript","javascript",{},true,1,"\u002Fjavascript\u002Farrays\u002Farray-methods",[23,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,93,97,101,105,109,113,117,121,125,129,133,137,141,145,149],{"id":24,"difficulty":25,"q":26,"a":27},"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":29,"difficulty":25,"q":30,"a":31},"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":33,"difficulty":25,"q":34,"a":35},"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":37,"difficulty":14,"q":38,"a":39},"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":41,"difficulty":14,"q":42,"a":43},"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":45,"difficulty":14,"q":46,"a":47},"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":49,"difficulty":25,"q":50,"a":51},"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":53,"difficulty":25,"q":54,"a":55},"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":57,"difficulty":14,"q":58,"a":59},"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":61,"difficulty":25,"q":62,"a":63},"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":65,"difficulty":14,"q":66,"a":67},"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":69,"difficulty":14,"q":70,"a":71},"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":73,"difficulty":14,"q":74,"a":75},"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":77,"difficulty":25,"q":78,"a":79},"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":81,"difficulty":14,"q":82,"a":83},"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":85,"difficulty":14,"q":86,"a":87},"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":89,"difficulty":90,"q":91,"a":92},"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":94,"difficulty":90,"q":95,"a":96},"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":98,"difficulty":14,"q":99,"a":100},"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":102,"difficulty":25,"q":103,"a":104},"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":106,"difficulty":25,"q":107,"a":108},"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":110,"difficulty":90,"q":111,"a":112},"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":114,"difficulty":25,"q":115,"a":116},"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":118,"difficulty":14,"q":119,"a":120},"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":122,"difficulty":14,"q":123,"a":124},"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":126,"difficulty":25,"q":127,"a":128},"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":130,"difficulty":90,"q":131,"a":132},"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":134,"difficulty":14,"q":135,"a":136},"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":138,"difficulty":14,"q":139,"a":140},"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":142,"difficulty":25,"q":143,"a":144},"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":146,"difficulty":90,"q":147,"a":148},"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":150,"difficulty":14,"q":151,"a":152},"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":11},"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","Arrays & Iteration","arrays","2026-06-18","Elw--T-gcVD4zuO2afQStkL-UYCKrtemiCrb2WELzjs",[162,163,166,170],{"subtopic":6,"path":21,"order":20},{"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":171,"path":172,"order":173},"Array Destructuring & Spread","\u002Fjavascript\u002Farrays\u002Fdestructuring-spread",4,{"path":175,"title":176},"\u002Fblog\u002Fjavascript-array-methods-map-filter-reduce","JavaScript Array Methods Explained — map, filter, reduce and the Iteration Toolkit",1781808676743]