Why Array Methods?
Array methods are built-in functions on JavaScript’s Array type that help you transform, search, aggregate, and mutate lists of values with clear, expressive code. Think of them as tiny superpowers that turn loops into readable one-liners.

Two Families: Mutating vs Non-Mutating
Mutating methods: change the original array in place (push,pop,shift,unshift,splice,sort,reverse,fill,copyWithin).Non-mutating methods: return a new array or value and leave the original unchanged (map,filter,slice,concat,flat,flatMap,toSorted,toReversed,toSpliced(new),reduce,some,every,find,findIndex,findLast,findLastIndex,includes,indexOf,lastIndexOf,join).
A pure function is one that has no side effects; many non-mutating methods help you write more functional code.
Let's test your knowledge. Click the correct answer from the options.
Which method mutates the original array?
Click the option that best answers the question.
- `map`
- `filter`
- `slice`
- `splice`
Core Trio: map, filter, reduce
map(fn): transform each element, returning a new array of equal length.filter(fn): keep elements where the predicate is true.reduce(fn, init): fold the array into a single value (sum, object, map).
xxxxxxxxxx// trio_demo.jsconst nums = [1, 2, 3, 4, 5];// Double then keep evens then sumconst doubled = nums.map(x => x * 2); // [2,4,6,8,10]const evens = doubled.filter(x => x % 4 === 0); // [4,8]const total = evens.reduce((acc, x) => acc + x, 0); // 12console.log({ doubled, evens, total });Build your intuition. Is this statement true or false?
map can change the length of the resulting array.
Press true if you believe the statement is correct, or false otherwise.
reduce Deep Dive (with Comments)
Build two results with a single pass using reduce: 1) sum of prices, 2) group items by category.
Accumulator is the carry-over value you return each iteration; its shape is up to you.
xxxxxxxxxxconst items = [ { name: 'apple', price: 1, category: 'fruit' }, { name: 'banana', price: 2, category: 'fruit' }, { name: 'carrot', price: 3, category: 'veg' }, { name: 'kale', price: 2.5, category: 'veg' },];const init = { sum: 0, groups: {} };const result = items.reduce((acc, item) => { // accumulate sum acc.sum += item.price; // accumulate groups const key = item.category; if (!acc.groups[key]) acc.groups[key] = []; acc.groups[key].push(item); return acc; // always return the accumulator!}, init);console.log(result);// { sum: 8.5, groups: { fruit: [...], veg: [...] } }Try this exercise. Could you figure out the right sequence for this list?
Put these steps of reduce in order:
Press the below buttons in the order in which they should occur. Click on them again to un-select.
Options:
- Return the accumulator
- Run reducer on current item
- Initialize accumulator
- Move to next item
Searching: find, some, every, includes
find(fn): first element that matches (orundefined).some(fn): is there any match? returns boolean.every(fn): do all match? returns boolean.includes(value, fromIndex=0): direct value presence check (uses===).
xxxxxxxxxx// searchers.jsconst users = [ { id: 1, name: 'Ana', active: true }, { id: 2, name: 'Bo', active: false }, { id: 3, name: 'Cy', active: true }];console.log(users.find(u => !u.active)); // {id:2,...}console.log(users.some(u => u.name.length > 2)); // trueconsole.log(users.every(u => typeof u.id === 'number')); // trueconst letters = ['a','b','c'];console.log(letters.includes('b')); // trueLet's test your knowledge. Fill in the missing part by typing it in.
__________ returns the index of the first matching element, while find returns the element itself.
Write the missing line below.
Slicing vs Splicing
slice(begin, end?): non-mutating copy of a subarray.splice(start, deleteCount, ...items): mutating insertion/removal.

xxxxxxxxxx// slice_vs_splice.jsconst a = [10,20,30,40,50];const b = a.slice(1, 4); // [20,30,40], a unchangedconst removed = a.splice(2, 2); // removes 30,40 → a becomes [10,20,50]console.log({ b, a, removed });Immutable Newcomers
Modern JS adds non-mutating versions of classic mutators:
toSorted(compareFn?)— likesortbut returns a new array.toReversed()— likereversebut non-mutating.toSpliced(start, deleteCount, ...items)— likesplice, but returns a new array.
xxxxxxxxxx// immutable_methods.jsconst a = [3,1,2];const sorted = a.toSorted((x,y) => x - y); // [1,2,3], a still [3,1,2]const rev = a.toReversed(); // [2,1,3], a still [3,1,2]const sp2 = a.toSpliced(1,1,'X'); // [3,'X',2], a unchangedconsole.log({ a, sorted, rev, sp2 });Sorting Gotchas
sort by default sorts lexicographically (as strings). Use a compare function for numeric sort.

xxxxxxxxxx// sort_numbers.jsconst nums = [10, 2, 5, 30];console.log(nums.sort()); // [10,2,30,5] (string sort!)console.log(nums.sort((a,b)=>a-b)); // [2,5,10,30] (numeric)Are you sure you're getting this? Click the correct answer from the options.
Which method both flattens and maps in one pass?
Click the option that best answers the question.
- `flat`
- `flatMap`
- `map`
- `concat`
flat and flatMap
flat(depth=1): flattens nested arrays up todepth.flatMap(fn): appliesmap, then flattens one level.
xxxxxxxxxx// flat_flatMap.jsconst nested = [1, [2, [3, [4]]]];console.log(nested.flat(1)); // [1,2,[3,[4]]]console.log(nested.flat(2)); // [1,2,3,[4]]console.log(nested.flat(99)); // [1,2,3,4]const words = ["hi", "yo"];console.log(words.map(w => w.split(""))); // [['h','i'], ['y','o']]console.log(words.flatMap(w => w.split(""))); // ['h','i','y','o']Joining and Splitting
join(sep=','): concatenate elements into a string.split(sep, limit?): (on strings) break into an array.
xxxxxxxxxx// join_split.jsconst cols = ['id','name','age'];const header = cols.join(','); // 'id,name,age'const row = "1,Ana,34".split(','); // ['1','Ana','34']console.log({ header, row });Aggregations You’ll Use Daily
These are every day aggregations you'll encounter daily, with examples.
xxxxxxxxxx// Sum/avg with reduceconst amounts = [4, 10, 7];const sum = amounts.reduce((a,b)=>a+b, 0);const avg = sum / amounts.length;// Max/min w/o Math.max(...spread) on huge arrays (safer for size)const max = amounts.reduce((m,x)=> x>m?x:m, -Infinity);const min = amounts.reduce((m,x)=> x<m?x:m, Infinity);// Unique values (dedupe) preserving first occurrenceconst arr = [3,5,3,2,5,9];const uniq = arr.filter((v,i,src) => src.indexOf(v) === i);// Frequency mapconst freq = arr.reduce((m,x)=> (m[x]=(m[x]||0)+1, m), {});console.log({ sum, avg, max, min, uniq, freq });Build your intuition. Is this statement true or false?
indexOf works for objects by structural equality.
Press true if you believe the statement is correct, or false otherwise.
Insertion & Removal Patterns (Immutable)
xxxxxxxxxx// immutable_crud.jsconst a = ['A','B','C','D'];// Insert 'X' at index 2 (no mutation)const insert2 = [a.slice(0,2), 'X', a.slice(2)];// Remove at index 1const remove1 = [a.slice(0,1), a.slice(2)];// Replace index 3 with 'Z'const replace3 = a.map((v,i)=> i===3 ? 'Z' : v);console.log({ a, insert2, remove1, replace3 });Performance & Pitfalls
O(n)nature: many array ops traverse the entire list; avoid repeatedconcatin loops—prefer onepushper item or build thenjoin.- Copy vs reference: methods like
slicecopy references for objects; nested structures still share inner objects. sortis in-place; prefertoSortedif immutability matters.
Project: CSV to Summary with Array Methods
Here, we parse a tiny CSV (no quotes/escapes) and summarize sales by product.
xxxxxxxxxxconst csv = `product,price,qtypen,1.50,4pen,1.50,2notebook,3.00,5stapler,5.00,1`.trim();// 1) split lines, 2) split fields, 3) map to records, 4) reduce to summaryconst [header, lines] = csv.split('\n');const cols = header.split(',');const records = lines .map(line => line.split(',')) .map(parts => Object.fromEntries(parts.map((v,i)=>[cols[i], v]))) .map(r => ({ product: r.product, price: +r.price, qty: +r.qty })); // castconst summary = records.reduce((acc, {product, price, qty}) => { const t = (acc[product] ||= { units: 0, revenue: 0 }); t.units += qty; t.revenue += price * qty; return acc;}, {});console.log(records);console.table(summary);Build your intuition. Click the correct answer from the options.
Which sequence keeps the original array unchanged while returning a sorted copy?
Click the option that best answers the question.
- `arr.sort()`
- `[...arr].sort()`
- `arr.toSorted()`
- Both B and C
Defensive Patterns
- Use
Array.isArray(x)to check arrayness;typeof [] === 'object'. - Destructure with defaults to avoid
undefinedissues in callbacks. - Prefer
Number.isFinitewhen parsing numeric arrays.
xxxxxxxxxx// defensive.jsfunction sumIfNumbers(maybes) { return maybes .filter(x => Number.isFinite(x)) .reduce((a,b)=>a+b, 0);}console.log(sumIfNumbers([1, 2, NaN, Infinity, '3'])); // 3Try this exercise. Fill in the missing part by typing it in.
The map callback receives three parameters: currentValue, index, and __________.
Write the missing line below.
Practice: Implement map & filter from Scratch
DO NOT use built-ins inside implementations; use simple loops.
Sparse array has “holes” (missing indices). Native methods skip them; we mirrored that.
xxxxxxxxxx// reimplement_map_filter.jsfunction myMap(arr, fn, thisArg) { const out = new Array(arr.length); for (let i = 0; i < arr.length; i++) { // skip holes in sparse arrays to emulate native semantics if (!(i in arr)) continue; out[i] = fn.call(thisArg, arr[i], i, arr); } return out;}function myFilter(arr, fn, thisArg) { const out = []; for (let i = 0; i < arr.length; i++) { if (!(i in arr)) continue; if (fn.call(thisArg, arr[i], i, arr)) out.push(arr[i]); } return out;}const nums = [1, , 3, 4]; // note the hole at index 1console.log(myMap(nums, x => x*2)); // [2, , 6, 8]console.log(myFilter(nums, x => x > 2)); // [3,4]One Pager Cheat Sheet
Array methodsare built-in functions on JavaScript’sArraytype that let you transform, search, aggregate, and mutate lists of values using clear, expressive code, effectively turning loops into readable one-liners.- JavaScript arrays fall into two families—mutating methods like
push,pop,splice,sort,reversethat change the original array in place, and non-mutating methods likemap,filter,slice,concat,reducethat return new values and leave the original unchanged, which helps you write pure functions and more functional code. - The
splicemethod mutates the original array by removing and/or inserting elements (and updating indices/length) and returns the removed elements, so it produces a side effect and is not a pure function, unlike non-mutating alternatives such asslice,map,concat, or the newertoSpliced(or you can build a new array withlet b = [...a.slice(0,i), ...newItems, ...a.slice(i+deleteCount)]). maptransforms each element producing a new array of the same length,filterkeeps elements that satisfy a predicate, andreducefolds the array into a single value (e.g., sum, object, map).mapalways preserves the original array length and index positions: it transforms each element by calling thecallback(returningundefinedstill yields an element) and — for sparse arrays — it does not call thecallbackfor holes so they remain, so to change the number of elements usefilterorflatMap.- Use
reduceto build two results in a single pass — a sum of prices and group items by category — by returning anAccumulator(the carry-over value) whose shape is up to you each iteration. - Initialize
accumulator
- Initialize
- Run
reduceron current item - Return the
accumulator - Move to next item
You must first initialize the accumulator (via an explicit initialValue or the first element) so the reducer can process each currentValue, return the updated accumulator to serve as the carry-over, and only then move to the next item, allowing reduce to perform single-pass computations by carrying a combined state.
- Use
find(fn)to return the first matching element (orundefined),some(fn)to test if any element matches (boolean),every(fn)to check if all elements match (boolean), andincludes(value, fromIndex=0)to check for direct value presence using strict equality (===). findreturns the element (orundefined) whilefindIndexreturns the index (or-1); both take apredicatecallback and short-circuit, so usefindfor the element value andfindIndexfor the position (e.g., tosplice/update), and note thatincludesdiffers by checking a value with===and returning a boolean—bothfindandfindIndexrun in O(n).slice(begin, end?)creates a non-mutating copy of a subarray, whereassplice(start, deleteCount, ...items)performs mutating insertion and/or removal of elements.- Modern JavaScript introduces non-mutating versions of classic mutators —
toSorted(compareFn?),toReversed(), andtoSpliced(start, deleteCount, ...items)— which return new arrays instead of modifying the original. - By default,
sortsortslexicographically(as strings), so use acompare functionfor numeric sort. flatMapcombines mapping and one-level flattening in a single pass by calling acallbackfor each element and immediately concatenating its (possibly array) result, which avoids creating an intermediate array thatmap(...).flat(1)would produce.flat(depth=1)flattens nested arrays up to the givendepth, whereasflatMap(fn)appliesmapthen flattens the result by one level.- Use
join(sep=',')to concatenate elements into a string andsplit(sep, limit?)(on strings) to break a string into an array. - A concise guide to aggregations you'll use daily, presenting common
aggregationswith practical examples. indexOfin JavaScript does not perform structural (deep) equality for objects; it relies on reference (identity) equality.- This section addresses insertion and removal patterns for immutable data structures.
- Performance & Pitfalls include the O(n) nature of many array operations, the distinction between copying vs referencing objects, and the importance of considering immutability when using the
sortmethod. - Project is focused on converting a small CSV file with no quotes or escapes into a summary of sales by product using
Array Methods. - Both B and C create a new (shallow) array copy of the original array using
slice()and the spread syntax, then usesortto return the sorted copy while leaving the original array unchanged. - When working with arrays, use
Array.isArray(x)for array checking, use destructuring with defaults to avoidundefinedissues, and preferNumber.isFinitewhen working with numeric arrays. - The
arrayparameter in amapcallback provides access to the original array being iterated over, allowing for contextual operations within the callback function. - map and filter functions were implemented from scratch without using built-in methods, with the consideration of handling
sparse arraysby skipping "holes" in the indices, similar to the behavior of native methods.

