14. JavaScript Array Methods
What you will learn
- How to transform arrays with
map,filter, andreduce - How to search with
find,some, andevery - How to sort safely
- How to copy and combine arrays
Methods that take a function
Many array methods accept a callback, a small function that runs once for each item. Arrow functions make these short. Most of these methods return a new array and leave the original unchanged.
forEach: do something for each item
Example
<ul id="demo"></ul>
<script>
const names = ["Sam", "Ali", "Mia"];
const list = document.getElementById("demo");
names.forEach((name) => {
const li = document.createElement("li");
li.textContent = name;
list.appendChild(li);
});
</script>
Output (after the script runs)
- Sam
- Ali
- Mia
map: transform every item
map returns a new array of the same length, with each item changed.
Example
<p id="demo"></p>
<script>
const prices = [10, 20, 30];
const withTax = prices.map((p) => p * 1.2);
document.getElementById("demo").textContent =
"Before: " + prices.join(", ") + " | After: " + withTax.join(", ");
</script>
Output (after the script runs)
Before: 10, 20, 30 | After: 12, 24, 36
filter: keep matching items
filter returns a new array containing only the items for which the callback returns true.
Example
<p id="demo"></p>
<script>
const ages = [12, 18, 25, 9, 40];
const adults = ages.filter((age) => age >= 18);
document.getElementById("demo").textContent = "Adults: " + adults.join(", ");
</script>
Output (after the script runs)
Adults: 18, 25, 40
reduce: combine into one value
reduce keeps a running result. You give it a starting value, and the callback receives the running total and the current item.
Example
<p id="demo"></p>
<script>
const cart = [4.5, 10, 2.25];
const total = cart.reduce((sum, price) => sum + price, 0);
document.getElementById("demo").textContent = "Total: " + total.toFixed(2);
</script>
Output (after the script runs)
Total: 16.75
find, some, and every
| Method | Returns |
|---|---|
find(fn) |
The first matching item, or undefined |
findIndex(fn) |
The position of the first match, or -1 |
some(fn) |
True if at least one item matches |
every(fn) |
True if all items match |
Example
<p id="demo"></p>
<script>
const scores = [45, 72, 88, 91];
document.getElementById("demo").innerHTML =
"First above 80: " + scores.find((s) => s > 80) + "<br>" +
"Any below 50: " + scores.some((s) => s < 50) + "<br>" +
"All above 40: " + scores.every((s) => s > 40);
</script>
Output (after the script runs)
First above 80: 88
Any below 50: true
All above 40: true
Sorting
sort() changes the original array. Without help it sorts as text, so numbers come out in the wrong order. Give it a compare function for numbers.
Example
<p id="demo"></p>
<script>
const nums = [10, 9, 100, 1];
const wrong = [...nums].sort();
const right = [...nums].sort((a, b) => a - b);
document.getElementById("demo").innerHTML =
"Default sort: " + wrong.join(", ") + "<br>" +
"Numeric sort: " + right.join(", ");
</script>
Output (after the script runs)
Default sort: 1, 10, 100, 9
Numeric sort: 1, 9, 10, 100
The three dots ... are the spread syntax. [...nums] makes a copy first, so the original is not changed. For text, use names.sort((a, b) => a.localeCompare(b)).
Chaining methods
Because filter and map return arrays, you can chain them.
Example
<p id="demo"></p>
<script>
const numbers = [1, 2, 3, 4, 5, 6];
const result = numbers
.filter((n) => n % 2 === 0) // 2, 4, 6
.map((n) => n * n); // 4, 16, 36
document.getElementById("demo").textContent = result.join(", ");
</script>
Output (after the script runs)
4, 16, 36
Copying and joining
slice(start, end)returns a copy of part of an array.concat(other)or[...a, ...b]joins arrays into a new one.reverse()reverses in place, so copy first if you need the original.
Common mistakes
- Sorting numbers without a compare function.
- Forgetting that
sortandreversechange the original array. - Forgetting the starting value in
reduce. - Forgetting to
returna value inside amapcallback written with braces. - Using
mapwhen you only want side effects. UseforEach.
Exercise
From the marks, keep those that are 50 or more, then show their average (rounded to one decimal place). The result should be 77.7.
Show solution
<p id="demo"></p>
<script>
const marks = [35, 80, 62, 91, 48];
const passed = marks.filter((m) => m >= 50);
const sum = passed.reduce((total, m) => total + m, 0);
const average = sum / passed.length;
document.getElementById("demo").textContent = "Average: " + average.toFixed(1);
</script>
Knowledge check
1. Which method returns a new array of the same length with every item changed?
map()
2. Why does [10, 9, 100, 1].sort() give a surprising result?
It sorts as text. Use a compare function such as (a, b) => a - b.
3. Which method tells you whether every item passes a test?
every()
Summary
maptransforms,filterselects, andreducecombines.find,some, andeverysearch with a test.- Sort numbers with a compare function, and copy first with
[...array].