- Learn
- Computer Science & IT
- Programming
- JavaScript Programming
- JavaScript Loops and Arrays
Loops and Arrays in JavaScript
for, while and do...while loops that run the right number of times, store values in arrays, and add, remove, search and change their elements. Process lists with for...of and with array methods such as map, filter, find and reduce, sort numbers and text in the order readers expect, and copy and combine arrays with spread syntax without changing the originals by accident.BeginnerLesson 2 of 9 in JavaScript Programming Course
What you will learn
- Write
for,whileanddo...whileloops that run the right number of times, trace them step by step, and control them withbreakandcontinue.- Count and repeat with a for loopWrite a
forloop from its three parts, trace its counter from the first to the last iteration, and build a running total. - Repeat while a condition holdsUse
whileanddo...whileloops when the number of repetitions is not known in advance, and make sure every loop can end. - Stop, skip and nest loopsLeave a loop early with
break, skip an iteration withcontinue, and place one loop inside another to work through grids and pairs.
- Count and repeat with a for loop
- Create arrays, read and change their elements by index, add and remove items, and search arrays or convert them to and from text.
- Create an array and read its elementsWrite array literals, read elements by their zero-based index, and use
lengthandat()to reach the last element. - Add, remove and replace elementsChange arrays in place with index assignment,
push,pop,shift,unshiftandsplice, copy parts withslice, and tell methods that change an array from methods that return a new one. - Search an array and convert it to and from textCheck whether an array contains a value, find a value's position, compare arrays correctly, and turn strings into arrays and back with
splitandjoin.
- Create an array and read its elements
- Visit every element of an array with
forandfor...ofloops, and use standard loop patterns to total, count, find and build results.- Walk through an array with for and for...ofChoose between an index-based
forloop andfor...of, get the index when you need it, and avoidfor...inand changing an array's length while looping over it. - Total, count, find and build with loop patternsApply the accumulator, counter, maximum, search and build-a-new-array patterns to real lists of data, and trace them step by step.
- Walk through an array with for and for...of
- Pass short arrow functions to array methods, and use
forEach,map,filter,find,some,everyandreduceto transform, select, search and summarize data.- Pass a function to an array methodWrite short arrow functions, know what a callback receives and must return, and use
forEachto run code for each element. - Transform and select elements with map and filterUse
mapto turn every element into a new value andfilterto keep the elements that pass a test, and chain the two. - Find elements and test conditionsUse
find,findIndex,findLast,findLastIndex,someandeveryto locate one element or check a condition across a list. - Combine all elements into one value with reduceUse
reducewith an accumulator and a starting value to compute totals, counts and extremes, and trace each step.
- Pass a function to an array method
- Sort numbers and text in the correct order, including the alphabetical order of the reader's language, and copy and combine arrays with spread syntax without changing the originals by accident.
- Sort and reverse arrays of numbers and stringsUse
sortwith a compare function, know thatsortchanges the array, and usetoSortedandtoReversedto get sorted or reversed copies. - Sort and present text for readers in any languageCompare strings with
localeCompareandIntl.Collatorfor natural alphabetical order, keep dates in a sortable form, and turn arrays into readable text withjoin,Intl.ListFormatand number formatting. - Copy and combine arrays with spread syntaxUnderstand that array variables refer to a shared array, and use spread syntax to copy, merge and insert arrays and to pass array elements to a function as separate values.
- Sort and reverse arrays of numbers and strings
JavaScript Loops and Arrays study guide
1Repeat code with loops
Repeating code needs a clear starting point, a test and a way to make progress. Counting loops make the number of steps visible; condition-based loops let the data decide when to stop. Trace each changing variable to see what runs before and after a check, then use early exits and nested loops to handle searches, skipped values and pairs. Small changes to an endpoint or an update can change the whole result.
1.1 Control a counting loop
A loop repeats a block of code. Each run of its body is an iteration. You can change how many times the work repeats by changing the loop's counter and condition, without copying the body.
Read the three parts
for (let i = 1; i <= 5; i++) {
console.log(i);
}
The parentheses contain an initialization, a condition and an update, separated by semicolons. let i = 1 runs once. JavaScript then checks i <= 5. If it is true, the body prints i, the update i++ adds 1, and JavaScript checks the condition again. A false condition ends the loop before another run of the body.
| Value before the check | Condition | Action |
|---|---|---|
1 | true | Print 1; update to 2 |
2, 3, 4 | true each time | Print each value and update |
5 | true | Print 5; update to 6 |
6 | false | Stop |
There are five iterations but six condition checks. The final failed check does not run the body. A loop whose condition is false at the start has no iterations.
Choose the endpoints and step
for (let i = 0; i < 10; i++) visits 0 through 9. Starting at 1 with i <= 10 visits 1 through 10. Both run ten times. For a step of 1 from a toward b, when b is at least a, < b gives b - a iterations and <= b gives b - a + 1.
The update can take larger steps: for (let i = 0; i <= 20; i += 5) visits 0, 5, 10, 15, 20. Counting backward needs both a decreasing update and a matching condition: for (let i = 3; i >= 1; i--) visits 3, 2, 1. Write down the first and last intended values before choosing < or <=; this catches an off-by-one error.
Keep a running total
let total = 0;
for (let i = 1; i <= 100; i++) {
total += i;
}
console.log(total); // 5050
total is an accumulator: it carries the result from one iteration into the next. After the first three iterations it holds 1, then 3, then 6. Put its declaration before the loop so it is initialized once. Declaring it inside the body would reset it each time and make it unavailable after the loop.
Diagnose a loop that behaves strangely
The header's counter uses let because i++ reassigns it. A const counter allows the first body run but throws a TypeError at the update. A let i declared in the header belongs to the loop; reading it afterward raises a ReferenceError unless another variable named i exists outside.
A semicolon immediately after the header gives the loop an empty body. In for (let i = 0; i < 3; i++); { console.log("Hello"); }, the block runs once after the loop. Keep the opening brace attached to the header. Finally, check the update's direction: starting at 0 with i < 5 and i-- moves away from the stopping point and never ends.
Key Takeaways
- Initialization runs once; the condition runs before each iteration; the update follows the body.
- Check the first and last counter values to catch an off-by-one error.
- Declare a running total before the loop so earlier work is retained.
- Use
letfor a counter that changes, and move it toward the stopping point.
1.2 Repeat until a condition changes
Some tasks end when a result reaches a target, not after a known number of steps. A while loop checks that stopping condition before each repetition. A do...while loop checks it after the body.
Check first with while
let balance = 1000;
let years = 0;
while (balance < 1500) {
balance = balance * 1.05;
years++;
}
console.log(years); // 9
The balance grows by 5% per year. Both variables are initialized before the loop. After eight repetitions the balance is about 1477.46, below the target, so another repetition is needed. After nine it is about 1551.33; the next check is false. Keep the full balance during the calculation and round only the displayed result.
If a while condition is false initially, the body runs zero times. For a simple counting loop, put the initialization before while and the update at the end of the body. This preserves a for loop's behavior when there is no continue. With continue, the update needs extra care because it may be skipped.
Run once before checking
let n = 4096;
let digits = 0;
do {
n = Math.floor(n / 10);
digits++;
} while (n > 0);
console.log(digits); // 4
Math.floor rounds down. Here each division removes the last digit: 4096 becomes 409, then 40, 4 and 0. Each removal increases digits. Starting with 0 still runs once, correctly counting its one digit. A prechecked while (n > 0) would skip that case and report zero digits. This digit-counting method is for nonnegative whole numbers.
| Loop | When the condition is checked | Minimum body runs |
|---|---|---|
while | Before the body | Zero |
do...while | After the body | One |
With let n = 10, a do...while body that prints n runs once even if its condition is n < 5. The same prechecked condition prints nothing. The semicolon belongs after the final condition in do...while.
Make progress toward an exit
An infinite loop keeps repeating without terminating. Forgetting n++ in let n = 0; while (n < 3) { console.log(n); } leaves the condition true forever. Long-running code can freeze a browser tab. Trace what changes the condition, and stop a stuck script with the browser's controls.
A compound condition such as attempts < 3 && !found continues only while both tests are true. It stops when three attempts have been used or a result is found. For a nonnegative integer decreasing toward zero, while (count > 0) makes a countdown clearer than while (count). Negative numbers are truthy too, so truthiness alone does not mean a count is positive.
Avoid equality as a decimal stopping test. Ten additions of 0.1 give 0.9999999999999999 in JavaScript, so while (x !== 1) can pass the intended endpoint forever. A comparison such as x < 1 permits crossing the boundary; an integer counter is better when exactly ten steps are needed. Compute each decimal value from that counter.
Key Takeaways
whilecan run zero times;do...whilealways runs at least once.- Choose a condition based on what must still happen, then change its inputs in the body.
- A compound condition can stop work when a limit is reached or a result is found.
- Floating-point rounding makes exact decimal equality a poor stopping test.
- Use whole-number counters when the number of repetitions must be exact.
1.3 Stop a search, skip work and visit pairs
A loop can leave before its condition becomes false or skip work for just one item. Nested loops let you repeat one sequence inside another, as when visiting rows and columns.
Break or continue
break leaves its loop immediately. To find the first multiple of 7 above 50:
for (let n = 51; n <= 100; n++) {
if (n % 7 === 0) {
console.log(n); // 56
break;
}
}
After printing 56, execution continues after the loop. Values 57 through 100 are never checked. while (true) can use the same pattern when the exit is easiest to test inside the body; a reachable break must provide the exit.
continue skips the rest of the current iteration. In a for loop it still runs the header's update before checking the condition again:
for (let i = 1; i <= 9; i++) {
if (i % 2 === 0) continue;
console.log(i);
}
The even values skip the print, so the output is 1, 3, 5, 7, 9. Replacing continue with break would end the loop at 2, leaving only 1 printed.
In a while loop, continue jumps directly to the condition. An update placed later in the body is skipped. If i is 2 and the body starts with if (i === 2) continue;, that value can remain stuck forever. Put the needed update before that jump or express counting with for.
Repeat an inner loop for each row
for (let row = 1; row <= 3; row++) {
let line = "";
for (let col = 1; col <= 4; col++) {
line = line + (row * col) + " ";
}
console.log(line.trim());
}
For row = 1, the inner loop visits columns 1 through 4 and builds the text "1 2 3 4". It starts over at column 1 for row 2, producing "2 4 6 8". Row 3 produces "3 6 9 12". The inner body runs twelve times: four columns for each of three rows. Declare line inside the outer body so each row starts with an empty string.
Use different names for the counters. An inner let i hides an outer i, making it hard to read both positions.
Visit each distinct pair once
For four people numbered 0 through 3, start the inner counter at i + 1:
for (let i = 0; i < 4; i++) {
for (let j = i + 1; j < 4; j++) {
console.log(i, j);
}
}
The pairs are 0–1, 0–2, 0–3, 1–2, 1–3, 2–3: six visits. Starting j at 0 would make sixteen visits, including self-pairs and reversed duplicates.
An ordinary break leaves only the innermost loop. To end a whole nested search, label the outer loop, for example outer: for (...), then use break outer; at the match. The label names the loop to leave; it does not change the order in which the pairs are tested.
Key Takeaways
breakends a loop;continueskips the rest of one iteration.continueruns aforupdate but can skip an update inside awhilebody.- The inner loop starts again for each outer iteration.
- Use
j = i + 1to visit each distinct pair once. - An ordinary
breakleaves the innermost loop. - A labeled
breakcan leave an outer loop as well.
2Store and change lists of data in arrays
A list has both values and positions. Arrays keep those values together while giving each one a numbered index. Reading, replacing, inserting and removing elements all depend on those positions, and edits can move later elements to new indexes. Learn what each method returns as well as what it changes, then choose searches and text conversions that produce the form of result the next step needs.
2.1 Read values and positions in an array
An array stores an ordered list under one name. Its values are called elements. An array literal uses square brackets and commas: const temps = [18, 21, 19, 24];. The literal [] creates an empty array.
Count positions from zero
const colors = ["red", "green", "blue"];
console.log(colors[0]); // "red"
console.log(colors[2]); // "blue"
console.log(colors.length); // 3
An element's index is its position starting from zero. The third element has index 2. length counts indexed slots, including any empty slots. For this gap-free array it is also the element count. The last index is colors.length - 1, so colors[colors.length - 1] reads "blue".
Reading colors[colors.length] asks for index 3, one past the end, and gives undefined. A missing index does not throw an error just because it is missing. colors[5] also gives undefined.
Read from the end
colors.at(-1) reads the last element and colors.at(-2) reads the one before it. Nonnegative indexes work as usual: colors.at(0) reads "red". A negative number in square brackets has a different meaning: colors[-1] does not count from the end and gives undefined for this array.
| Expression | Result |
|---|---|
colors[1] | "green" |
colors.at(-1) | "blue" |
colors[3] | undefined |
colors[-1] | undefined |
Read a list inside a list
An element can itself be an array:
const grid = [[1, 2, 3], [4, 5, 6]];
console.log(grid[1]); // [4, 5, 6]
console.log(grid[1][0]); // 4
The first index selects a row. The second selects a value inside that row. grid.length is 2, while grid[0].length is 3. These lengths describe different arrays. Rows in a nested array can have different lengths.
Arrays can mix types, as in [42, "km", true]. A list of one kind of data, such as temperatures, is easier to process because each element can be handled in the same way.
Recognize an array and avoid empty-slot surprises
typeof [1, 2] returns "object", so it is not a specific array test. Use Array.isArray(value): it returns true for [1, 2] and false for "12".
new Array(3) creates three empty slots; it does not store the single number 3. Use [3] for one element or [0, 0, 0] for three explicit zeros. An empty slot reads as undefined, but it is a gap, not an explicitly stored value. Writing array literals makes the intended contents clear.
Read strings without trying to change them in place
Strings also support indexing, length and at(). "hello"[1] is "e" and "hello".at(-1) is "o". Strings are immutable: assigning to a character position does not replace it. In strict mode, including JavaScript modules, that assignment throws a TypeError. Build a new string when text needs to change.
Key Takeaways
- Indexes start at
0; the last index islength - 1. at(-1)reads the last element;arr[-1]does not.- Read nested arrays one index at a time.
- Use
Array.isArrayto identify arrays. - Array literals distinguish stored values from empty slots.
2.2 Change an array or copy part of it
Changing an existing array is called mutation. Some methods mutate the array; others return a new array. A method's return value may also be a length or a removed element, so check both the array and the result of the call.
Replace elements and change the ends
const scores = [70, 80, 90];
scores[1] = 85;
console.log(scores); // [70, 85, 90]
const keeps scores pointing to the same array. It does not freeze that array's contents. Assigning scores = [] would throw a TypeError, but index assignment is allowed.
| Method | Change | Return value |
|---|---|---|
push(...items) | Add at the end | New length |
pop() | Remove from the end | Removed element |
unshift(...items) | Add at the start | New length |
shift() | Remove from the start | Removed element |
For const queue = ["Ana", "Ben"];, queue.push("Cleo") returns 3. The array becomes ["Ana", "Ben", "Cleo"]. Then queue.pop() returns "Cleo" and leaves the first two names. Storing a call to push stores its numeric length, not the updated array. pop and shift return undefined on an empty array. Adding or removing at the start also shifts the other indexes, which can involve more work on long arrays.
Insert and remove in the middle
splice(start, deleteCount, ...items) changes the array and returns an array of removed elements:
const days = ["Mon", "Tue", "Thu", "Fri"];
const removed = days.splice(2, 0, "Wed");
// days: ["Mon", "Tue", "Wed", "Thu", "Fri"]
// removed: []
const nextRemoved = days.splice(1, 2);
// days: ["Mon", "Thu", "Fri"]
// nextRemoved: ["Tue", "Wed"]
The first call starts at index 2, deletes zero items and inserts "Wed" there. The second starts at index 1 and removes two items. Its second argument is a count, not an ending index. Elements after an insertion or removal receive new indexes.
Copy a range with slice
slice(start, end) returns a new array and excludes the ending index. For const t = [10, 20, 30, 40, 50];, t.slice(1, 3) gives [20, 30] and leaves t unchanged. t.slice(-2) copies the last two elements, [40, 50]. With no arguments, t.slice() copies the whole array. The extra letter in splice marks a different operation: it edits the original; slice copies a range.
Keep the list free of accidental gaps
Writing beyond the end creates empty slots. After const a = [1, 2]; a[4] = 5;, the length is 5 and indexes 2 and 3 are gaps. delete a[i] also leaves a gap and preserves the length. Use push to append and splice(i, 1) to remove an element and close the gap.
Assigning a smaller length removes elements from the end. a.length = 0 empties the array. The removed elements do not reappear if the length is later increased.
sort and reverse also mutate arrays. Copying methods include slice, concat, map, filter, toSorted, toReversed, toSpliced and with. When a method returns a new array, save or use that result; the original still holds its earlier contents.
Key Takeaways
constprevents reassignment of the variable but allows array mutation.pushandunshiftreturn lengths;popandshiftreturn removed elements.spliceedits in place and returns the removed elements.slicecopies a range whose ending index is excluded.deleteleaves a gap;splice(i, 1)closes it.- Setting a smaller
lengthremoves elements from the end. - Keep the result of a copying method when you need the new array.
2.3 Search values and turn lists into text
A search may need a yes/no result or an element's position. Text conversion has another purpose: it changes the form of data so a list can be read, stored or processed.
Ask whether or where
includes(value) returns a boolean. ["tea", "coffee"].includes("tea") is true; changing the search to "Tea" gives false. Text matching is case-sensitive, and types matter: [5].includes("5") is false.
indexOf(value) returns the first matching index, or -1 when no value matches. lastIndexOf searches from the end. With [3, 7, 3, 9], the first 3 is at index 0 and the last is at index 2. Searching for 5 returns -1.
Do not write if (arr.indexOf(x)). Index 0 is falsy, while -1 is truthy: that test rejects a match at the start and accepts a missing value. Use arr.indexOf(x) !== -1, or use includes when the position is unneeded.
For ordinary values, both methods require the same type and value, like strict equality. Their treatment of NaN differs: [1, NaN].includes(NaN) is true, but [1, NaN].indexOf(NaN) is -1. The equality rule used by includes can match NaN to itself.
Compare contents deliberately
Two separately created arrays are different arrays even when their elements match. [1, 2] === [1, 2] is false; == also compares array identity. To check the same ordered contents, compare lengths and then the values at each matching index. A yes/no membership check alone would not establish the same order or the same number of repetitions.
Join elements into a string
const dateParts = ["2026", "03", "15"];
console.log(dateParts.join("-")); // "2026-03-15"
console.log([1, 2, 3].join()); // "1,2,3"
console.log([1, 2, 3].join("")); // "123"
join places its separator between elements, never after the last one. Its default separator is a comma without spaces. null and undefined elements contribute empty text. Choose the separator explicitly for readable output.
Using + with a string also converts an array to text, but uses commas: "List: " + [1, 2] becomes "List: 1,2". Nested structure is lost in that text: String([1, [2, 3]]) gives "1,2,3". Log the array itself to inspect its structure.
Split text into pieces
"red,green,blue".split(",") returns ["red", "green", "blue"]. The separator must match exactly. Splitting "red, green" on just a comma retains the space at the start of " green"; splitting on ", " removes the comma and that space.
"4,8,15".split(",") returns strings, not numbers. Convert each piece before adding numeric values. Otherwise the + operator can join text instead of finding a total.
For simple letter-based text, "stressed".split("").reverse().join("") produces "desserts". The split makes a fresh array, reverse changes that array, and join rebuilds a string. An empty separator splits UTF-16 code units; some symbols use more than one unit, so this is not a general way to reverse all human-readable text.
Key Takeaways
- Use
includesfor membership andindexOforlastIndexOffor positions. - Compare a search index with
-1; do not use its truthiness. - Separate arrays compare by identity, even when their values look identical.
joincreates text;splitcreates an array of strings.- Spaces belong to the separator only when you include them explicitly.
- Convert numeric text before arithmetic.
3Loop through arrays
Working through a list is easier when the loop exposes the right information. Sometimes the body needs only each value; sometimes it needs an index, a previous value or a backward path through the array. Build reusable patterns for totals, counts, searches and new lists, and watch how each result changes after an iteration. These patterns also explain the array methods that follow.
3.1 Visit array values without skipping them
A loop can visit array positions or take the values directly. Choose the form that exposes the information the body needs. Keep the array's changing indexes in mind when inserting or removing elements.
Use indexes for positions and direction
const fruits = ["apple", "pear", "plum"];
for (let i = 0; i < fruits.length; i++) {
console.log(fruits[i]);
}
The indexes are 0, 1, 2. The test is < fruits.length, because index 3 is past the end. With <=, an extra iteration would read undefined. Index loops can also go backward, starting at fruits.length - 1 and continuing while i >= 0, or visit every second element with i += 2.
Use for...of for values
for (const fruit of fruits) {
console.log(fruit.toUpperCase());
}
This prints "APPLE", "PEAR" and "PLUM". fruit holds one value per iteration. const works because each iteration creates a new binding; the loop does not reassign one shared counter. for...of works on strings too. A loop over "banana" can count vowels by testing "aeiou".includes(ch) for each ch.
Changing a local number does not write into the array. After for (let n of nums) { n = n * 2; }, the numeric elements of nums are unchanged. To mutate them, assign through nums[i], or build a new array of doubled numbers.
Get values and indexes together
entries() supplies pairs containing an index and a value. Square brackets in the loop header unpack each pair:
for (const [i, fruit] of fruits.entries()) {
console.log((i + 1) + ". " + fruit);
}
The output is "1. apple", "2. pear", "3. plum". Array indexes still start at zero; i + 1 changes only the displayed numbering.
| Need | Useful loop |
|---|---|
| Each value in order | for...of |
| Positions, reverse order or neighbors | Index-based for |
| Value and index together | for...of over entries() |
for...in visits property names. For arrays, its indexes are strings, and it can include extra properties. Use the array loop forms above to process elements.
Avoid skipping shifted elements
const nums = [2, 4, 5, 6];
for (let i = 0; i < nums.length; i++) {
if (nums[i] % 2 === 0) nums.splice(i, 1);
}
// nums is [4, 5]
At index 0, removing 2 shifts 4 into index 0. The update moves i to 1, so 4 is skipped. The loop then sees 5 and removes 6. The result still contains an even number.
When removing by index, loop backward from the end. Removing an element then shifts only positions already visited. Another approach is to build a new array containing the values to keep. Avoid adding elements to the same array while a loop's stopping test depends on its length; the endpoint can keep moving.
Key Takeaways
- Visit indexes from
0whilei < arr.length. - Use
for...ofwhen only values are needed. entries()supplies index-value pairs.- Reassigning a local numeric loop variable does not replace an array element.
- Forward removal can skip shifted elements; loop backward or build a new array.
3.2 Build totals, searches and new lists
Many array tasks use the same small loop patterns. Decide what result you need, choose its starting value, and update it once for each relevant element. A trace shows what the result means after each step.
Accumulate a total and count matches
const temps = [18, 21, 19, 24];
let sum = 0;
let warm = 0;
for (const t of temps) {
sum += t;
if (t > 20) warm++;
}
sum adds each temperature; warm adds one only for a temperature above 20 °C. They track different quantities. A trace makes that distinction visible:
t | sum after adding | warm after checking |
|---|---|---|
18 | 18 | 0 |
21 | 39 | 1 |
19 | 58 | 1 |
24 | 82 | 2 |
The average is sum / temps.length, giving 20.5 °C. Check the length before dividing: an empty array gives 0 / 0, which is NaN, not a meaningful average.
Track a largest or smallest value
For a nonempty array, initialize the maximum from its first element. Then replace it only when a larger value is found:
const values = [-3, -7, -1, -5];
let max = values[0];
for (const n of values) {
if (n > max) max = n;
}
// max is -1
Starting at zero would incorrectly retain zero for an all-negative list. Starting at -Infinity also works for a maximum, but an empty input then leaves that starting value. For a minimum, reverse the comparison and choose the first element or Infinity as the start.
Find a first match or test a whole list
A search stores a match and exits with break. With let firstWarm;, the loop can assign firstWarm = t at the first t > 20 and break. It finds 21, leaving later elements unchecked. If nothing matches, the variable stays undefined.
For an "all" test, start a flag at true and set it to false at the first failure. For an "any" test, start at false and set it to true at the first success. With passing scores defined as at least 50, [72, 85, 49] fails the all-passed test at 49. An empty list leaves the starting flag unchanged.
Build changed values and compare neighbors
const km = [1.5, 3, 0.25];
const meters = [];
for (const d of km) {
meters.push(d * 1000);
}
// meters is [1500, 3000, 250]
The new array starts empty and receives one converted distance per iteration. Put a condition before push when only some values belong in the result.
For day-to-day changes, start at index 1, because index 0 has no previous day:
const changes = [];
for (let i = 1; i < temps.length; i++) {
changes.push(temps[i] - temps[i - 1]);
}
// changes is [3, -2, 5]
There is one fewer difference than readings. Subtracting in the opposite order would reverse every sign. The same result shapes appear in array methods: map builds transformed values, filter keeps matches, find searches, some and every test, and reduce accumulates. A loop remains useful when one pass needs several results, as with sum and warm.
Key Takeaways
- Start totals and counts at zero, then update each for its own purpose.
- Initialize an extreme from the data or an appropriate infinity.
- A first-match search stops with
break. - All/any flags start with opposite boolean values.
- Build a new array with
pushto preserve the original. - Start neighbor comparisons at index
1. - Trace changing variables to find where a result first goes wrong.
4Process arrays with callback methods
Array methods let a short function describe what should happen to each value. The method manages the traversal while the callback supplies a transformation, a test or the next running result. Read the returned value carefully: it may be an array, an element, an index, a boolean or a total. The same few callback rules support all of these tasks, including reliable behavior when a list is empty.
4.1 Give an array method a callback
A function takes inputs, runs code and can return a result. A callback is a function handed to another function to call. Array methods use callbacks to describe the work for each element.
Write a short arrow function
n => n * 2 takes a parameter named n and returns its doubled value. The arrow separates the inputs from the body. A single parameter can omit parentheses. Zero or multiple parameters need them: () => 0 and (a, b) => a - b.
const double = n => n * 2;
const doubled = [1, 2, 3].map(double);
// doubled is [2, 4, 6]
double names the function itself. The method calls it with each number. Writing map(double()) would call it immediately and pass the result instead of the function. With a named test such as function isEven(n) { return n % 2 === 0; }, use filter(isEven) to let the method supply each element.
Return from a block body
An expression after the arrow is returned automatically. Curly braces create a block, so a result needs an explicit return:
const double = n => {
const doubled = n * 2;
return doubled;
};
Without return, the function returns undefined. [1, 2, 3].map(n => { n * 2; }) therefore produces [undefined, undefined, undefined]. The multiplication runs, but its value never becomes the callback's result.
Read callback arguments by position
Methods such as map, filter and forEach pass the element first, its zero-based index second, and the whole array third. In (name, i) => ..., the names are your choice; their positions determine what they receive. Leave off unused parameters from the end. Other methods have different signatures: reduce also receives an accumulator, and a sorting callback receives two values to compare.
Use forEach for actions
const letters = ["a", "b"];
const result = letters.forEach((letter, i) => {
console.log(i + ": " + letter);
});
// Prints "0: a" and "1: b".
// result is undefined.
Printing is a side effect: an action performed while the callback runs. forEach discards callback return values and itself returns undefined. Use map when a new array of results is needed. Returning a value from a forEach callback does not change that rule.
A return in this callback ends only the current call; the method continues to the next element. break cannot be used inside a callback to exit forEach. Choose for...of with break, or a search method such as find or some, when later work should stop at a match.
These callback methods do not themselves edit the source array. The callback can still mutate it, for example through index assignment or push. Keeping callbacks focused on their returned value or intended action makes it easier to reason about what the source will contain afterward.
Key Takeaways
- Pass a callback function itself, without calling it first.
- An expression body returns its value automatically; a block body needs
return. - Callback parameter positions determine their meanings.
forEachperforms actions and returnsundefined.
4.2 Transform every value or keep matching values
Choose an array method by the shape of the result. map produces a value for every present element. filter keeps the original elements that pass a test. Both return new arrays.
Transform with map
const km = [1.5, 3, 0.25];
const meters = km.map(d => d * 1000);
// meters is [1500, 3000, 250]; km is unchanged.
The callback's return becomes the element at the matching position. For a gap-free input there is one callback call per element, and the result has the same length. Mapping string elements works too: ["ana", "ben"].map(s => s.toUpperCase()) gives ["ANA", "BEN"].
The second callback parameter gives the index. ["Ana", "Ben"].map((name, i) => (i + 1) + ". " + name) builds ["1. Ana", "2. Ben"]. If the callback has a block body, explicitly return the value to store.
Select with filter
const temps = [18, 21, 19, 24];
const warm = temps.filter(t => t > 20);
// warm is [21, 24]
filter keeps an element when the callback returns a truthy result. It keeps the element itself, not the callback's boolean. The retained values stay in their original order. The result can contain all elements, some, or none; temps.filter(t => t > 30) is [].
Do not return the element itself when zero is valid data. [0, 5, 0, 3].filter(n => n) drops both zeros because they are falsy. A condition such as n !== null removes missing readings represented by null while preserving zero. State the actual rule for keeping an element.
| Result needed | Method |
|---|---|
| One transformed value per element | map |
| All original elements passing a test | filter |
| Some elements, then transformed | filter followed by map |
Using map with a conditional that returns undefined for rejected elements does not remove them. Those undefined results still occupy positions in the new array.
Follow a chain left to right
[12, 7, 30, 4].filter(n => n >= 10).map(n => n / 2) first creates [12, 30], then [6, 15]. The second callback receives only the retained elements. Filtering before mapping is appropriate when the test refers to the original values. Changing the order can change what the test sees.
Convert numeric text deliberately
const numbers = "4,8,15".split(",").map(Number);
// numbers is [4, 8, 15]
Number receives each text piece and produces a number. Passing parseInt directly is a trap: its second argument is a number base, while map supplies the index there. ["10", "10", "10"].map(parseInt) gives [10, NaN, 2]. Use map(s => parseInt(s, 10)) to fix the base, or map(Number) for these whole numeric strings.
Neither map nor filter replaces the source. temps.map(t => t + 1); alone throws away its newly calculated array. Save it, return it from a function, or use it in a chain.
Key Takeaways
mapreturns transformed values in a new array of the same length.filterreturns matching original elements in their existing order.- A filter test must express the intended rule so valid zeros are retained.
- Chained callbacks operate on the previous method's result.
- Use
Numberor a one-argument wrapper instead ofmap(parseInt). - Store or use the new array; the source is unchanged.
4.3 Find one match and ask any or all
Some questions need one value, others a position or a yes/no answer. Search methods can stop once that answer is known. Choosing the right return type makes later conditions easier to write correctly.
Choose a value or an index
const temps = [18, 21, 19, 24];
console.log(temps.find(t => t > 20)); // 21
console.log(temps.findIndex(t => t > 20)); // 1
console.log(temps.findLast(t => t > 20)); // 24
console.log(temps.findLastIndex(t => t > 20)); // 3
find searches from the start and returns the first matching element. findIndex returns its index. Their Last forms search backward. All four stop when they find the requested match.
| Method | Match result | No-match result |
|---|---|---|
find, findLast | Element | undefined |
findIndex, findLastIndex | Index | -1 |
filter | Array of all matches | [] |
temps.find(t => t > 30) returns undefined; temps.findIndex(t => t > 30) returns -1. Before passing a found index to splice, check i !== -1. Otherwise, splice(-1, 1) removes the last element even though no match was found.
Preserve falsy matches
[3, 0, 5].find(n => n < 1) returns 0, a successful match. if (result) wrongly treats it as failure because zero is falsy. For numeric data, result !== undefined distinguishes zero from no match. If an array can itself contain undefined as a matching value, use findIndex and compare the result with -1; the value alone cannot distinguish those cases.
filter is appropriate when all matches are needed. [5, 12, 8, 130].filter(n => n > 10) gives [12, 130]; find returns just 12. Getting filter(...)[0] computes the entire matching array before reading its first value.
Test any or all
const scores = [72, 85, 49];
const anyFailed = scores.some(s => s < 50); // true
const allPassed = scores.every(s => s >= 50); // false
some stops at the first success. every stops at the first failure. Their answers are booleans, not elements. In these calls the 49 makes some succeed and every fail.
For an empty array, some returns false because nothing passes. every returns true because nothing fails. If a completed set of results must contain at least one score, combine the tests: scores.length > 0 && scores.every(s => s >= 50). The length condition handles emptiness; every checks the elements.
Choose exact membership or a custom test
includes("ana") looks for exactly that value. A case-insensitive search needs a callback: names.some(n => n.toLowerCase() === "ana"). This can accept both "Ana" and "ANA". Use includes for a known value, and a callback search when each element must be tested by a rule.
Key Takeaways
- Choose value, index, array or boolean according to the result you need.
findLastandfindLastIndexsearch from the end.- Test an index against
-1before using it to edit an array. - A falsy element such as
0can be a real match. somestops at a success;everystops at a failure.- Empty arrays give
falseforsomeandtrueforevery.
4.4 Carry one result through reduce
reduce carries an accumulator from one element to the next. Its callback returns the accumulator for the following step. After the last element, the method returns that final value.
Trace a total
const temps = [18, 21, 19, 24];
const total = temps.reduce((sum, t) => sum + t, 0);
// total is 82
The 0 is the initial accumulator. The callback receives sum first and the current temperature t second. Its returned sum becomes the next call's first argument.
| Accumulator before | Element | Returned accumulator |
|---|---|---|
0 | 18 | 18 |
18 | 21 | 39 |
39 | 19 | 58 |
58 | 24 | 82 |
This is the same running total as a loop with let sum = 0. A callback also has optional index and array arguments after the accumulator and element. Parameter names are flexible, but their order is fixed.
Supply a useful starting value
With an initial value, reduction starts at the first element. Without one, the first present element becomes the accumulator and callback calls start with the next present element. On an empty array, omitting the initial value throws a TypeError. [].reduce((sum, n) => sum + n, 0) safely returns 0 because no callback call is needed.
The start also establishes the kind of result. Use 0 for totals or counts and "" for text. ["a", "b", "c"].reduce((text, s) => text + s.toUpperCase(), "") builds "ABC". A numeric total that starts with a string can accidentally concatenate text through +.
Count and find an extreme
const scores = [72, 85, 49];
const passed = scores.reduce(
(count, s) => s >= 50 ? count + 1 : count,
0
);
// passed is 2
Passing adds one; failing returns the unchanged count. Every branch supplies a next accumulator. For a maximum, return the larger value: [-3, -7, -1, -5].reduce((max, n) => n > max ? n : max, -Infinity) gives -1. Starting at zero would be wrong for this all-negative list. Empty input leaves -Infinity, so handle that outcome when a real maximum is required.
Return on every path
A block callback needs return. (sum, n) => { sum + n; } returns undefined, so the reduction's final result is undefined. A partly missing return is also dangerous. In a count over [72, 49, 85], returning only for a pass gives 1 first, then undefined at 49, then NaN when adding one at 85. Return the unchanged accumulator when an element makes no contribution.
Combine operations without hiding the task
The total of passing scores is scores.filter(s => s >= 50).reduce((sum, s) => sum + s, 0), which gives 157. An average needs a separate count: temps.reduce((sum, t) => sum + t, 0) / temps.length gives 20.5 °C. Check the length first, because empty input gives NaN after division. If a callback starts doing several unrelated jobs, a for...of loop can show the changing results more clearly.
Key Takeaways
reducepasses the accumulator first and the element second.- The callback must return the next accumulator on every path.
- An explicit initial value makes empty-input behavior predictable.
- Choose the starting value for the result: total, count, text or extreme.
- An average needs both a total and a nonzero count.
5Sort, copy and combine arrays
Ordering a list and copying it are separate choices. A numeric sort needs different comparison rules from a list of names, and language affects the order readers expect. Decide whether the original sequence must be preserved before choosing an editing or copying method. References and shallow copies explain which later changes stay local and which remain visible through another array name.
5.1 Sort numbers and preserve the original
Sorting chooses an order by comparing elements. Reversing simply flips the existing order. Both operations have methods that edit an array and methods that create a copy.
Understand the default order
[10, 9, 1, 100].sort() gives [1, 10, 100, 9]. Without a compare function, sort compares elements as strings, character by character using UTF-16 code units. "100" starts with "1", which comes before "9". The stored elements remain numbers; only the comparison uses their text form.
For strings, this default can also surprise readers. ["banana", "Cherry", "apple"].sort() gives ["Cherry", "apple", "banana"], because capital ASCII letters come before lowercase ones. Accented letters can be separated from the letters readers group them with. Use language-aware comparison for human alphabetical order.
Return the right sign
A compare function receives two elements, a and b. A negative return places a before b; a positive return places it after b; zero treats them as equal for sorting.
const nums = [10, 9, 1, 100];
nums.sort((a, b) => a - b);
// nums is [1, 9, 10, 100]
Comparing 10 with 9 produces positive 1, so 9 goes before 10. For descending numeric order, use (a, b) => b - a. Return a number with a meaningful sign. (a, b) => a > b returns only true or false, which become 1 or 0; it never reports that a belongs before b. Such a comparator gives unreliable ordering.
Sorting is stable: elements comparing as equal keep their original relative order. ["kiwi", "fig", "pear", "plum"].sort((a, b) => a.length - b.length) gives ["fig", "kiwi", "pear", "plum"]. The three four-letter words retain their order.
Choose mutation or a copy
| Method | Effect on source | Returned array |
|---|---|---|
sort(compare) | Sorts source in place | Same array |
toSorted(compare) | Leaves source unchanged | New sorted array |
reverse() | Reverses source in place | Same array |
toReversed() | Leaves source unchanged | New reversed array |
const sorted = scores.sort((a, b) => a - b); gives a second name for the same now-sorted array. It does not preserve the earlier order. For a new sorted array, use scores.toSorted((a, b) => a - b), or make a spread copy before sort.
[3, 1, 2].toReversed() gives [2, 1, 3]. That is a reversed sequence, not descending numeric order. To put largest values first, use a descending comparator or sort ascending before reversing.
Check types before sorting numeric text
Values from split are strings. ["10", "9", "100"].sort() gives ["10", "100", "9"]. Subtraction in a comparator converts numeric strings during comparison but leaves the elements as strings. Convert first with map(Number) when the values are numeric data, then use a numeric comparator. This also prepares the data for later addition without accidental text concatenation.
Key Takeaways
- Default sorting compares text, even for numeric elements.
- Use
a - bfor ascending numbers andb - afor descending numbers. - A comparator returns a negative number, zero or a positive number.
- Equal comparisons preserve relative order.
sortandreversemutate;toSortedandtoReversedcopy.- Reversing the current order does not necessarily sort it.
5.2 Order and format data for the reader
People expect text order and number formatting to follow a language's conventions. Keep values in forms that are easy to process, choose an explicit locale for text comparison, and format the final output for the reader.
Compare text with locale rules
a.localeCompare(b, locale) returns a negative number when a comes before b, a positive number when it comes after, and zero when they compare as equal. Only the sign is guaranteed, not an exact -1 or 1.
const names = ["Zoe", "Émile", "adam"];
const sorted = names.toSorted((a, b) => a.localeCompare(b, "en"));
// sorted is ["adam", "Émile", "Zoe"]
A locale is a language tag such as "en", "de" or "sv". German places "ä" before "z", while Swedish places it after "z". Pass the page's intended language to make that choice explicit. Without a locale, the runtime's default settings decide the order.
Plain < comparisons still compare character codes. Subtracting words produces NaN, which acts like an equal comparison in sorting; it does not create alphabetical order.
Set useful comparison options
With { numeric: true }, runs of digits compare numerically. Sorting ["file10", "file2", "file1"] with (a, b) => a.localeCompare(b, "en", { numeric: true }) gives ["file1", "file2", "file10"]. A plain text sort puts "file10" before "file2".
In English, { sensitivity: "base" } treats case and accent variants such as "a", "A" and "á" as equal. These rules depend on the language: Swedish treats "a" and "ä" as different base letters. Use the intended locale when matching as well as when sorting.
For many comparisons, reuse a collator:
const collator = new Intl.Collator("en", { numeric: true });
const sorted = files.toSorted(collator.compare);
collator.compare is already a comparison function. Creating it once avoids repeatedly setting up the same locale options during a large sort.
Sort dates before formatting them
Fixed-width YYYY-MM-DD strings put the year before the month and day. Text sorting then follows date order: ["2026-03-15", "2025-11-02", "2026-01-20"].sort() gives ["2025-11-02", "2026-01-20", "2026-03-15"].
Day-first text such as "15/03/2026" and "20/01/2025" compares the day first, so it can put the later year first. Store and sort these dates in ISO form, then produce display text at the end.
Build readable lists and numbers
join(", ") uses the same separator everywhere. Intl.ListFormat adds the language's final connector:
const list = new Intl.ListFormat("en-US", {
style: "long", type: "conjunction"
});
list.format(["Ana", "Ben", "Cleo"]);
// "Ana, Ben, and Cleo"
"en-GB" produces "Ana, Ben and Cleo"; "nl" produces "Ana, Ben en Cleo". A disjunction uses "or" in English. Two names give "Ana and Ben" without a comma.
(1234.5).toLocaleString("en-US") gives "1,234.5", while "de-DE" gives "1.234,5". These results are strings. Sort numeric data before applying toLocaleString with map; formatting first replaces numeric values with text whose punctuation affects text sorting.
Key Takeaways
- Use
localeCompareor a reusableIntl.Collatorfor language-aware order. - Use the sign of the comparison result, not an exact
-1or1. numeric: trueorders digit sequences naturally inside names.- Fixed-width ISO date strings sort chronologically as text.
Intl.ListFormatadds a language-appropriate connector.- Sort numbers first and format them last.
5.3 Copy arrays without sharing accidental changes
An array variable holds a reference to an array. Assigning that variable to another name shares the array. Spread syntax can create a new outer array, combine lists or pass elements as separate function arguments.
Separate assignment from copying
const a = [1, 2, 3];
const b = a;
b.push(4);
// a and b both refer to [1, 2, 3, 4].
console.log(a === b); // true
There is one array with two names. const does not prevent either name from being used to mutate it. A new outer array needs an actual copying operation:
const c = [...a];
c.push(5);
// c is [1, 2, 3, 4, 5]; a stays [1, 2, 3, 4].
console.log(c === a); // false
The three dots lay out a's elements inside a new array literal. Leaving them out has a different effect: [a] creates a one-element array whose element is the entire array a. [...a] contains a's elements individually.
Combine and insert
[...[1, 2], ...[3, 4]] gives [1, 2, 3, 4], as does [1, 2].concat([3, 4]). [...first, 99, ...second] places one extra element between two lists. [...list, "new"] creates an extended array while list.push("new") edits the existing one. Spread preserves the element order of each input.
Recognize a shallow copy
const grid = [[1, 2], [3, 4]];
const copy = [...grid];
copy[0].push(9);
// grid[0] and copy[0] are both [1, 2, 9].
The outer arrays differ, but their row elements still point to the same inner arrays. This is a shallow copy. Replacing copy[0] with a new row would change only the copied outer array; mutating the existing row changes the shared row. structuredClone(grid) makes an independent deep copy of these nested arrays.
Spread values into a call
Math.max(...[3, 9, 4]) supplies three separate arguments and returns 9. Passing the array directly, Math.max([3, 9, 4]), supplies one array and gives NaN. Empty spread gives Math.max(...[]) === -Infinity and Math.min(...[]) === Infinity.
Very large arrays can exceed an engine's argument limit when spread into a call. There is no universal safe element count. Use a loop or reduce to find an extreme for a large input. Spread in an array literal does not create a function-argument list.
Spread strings and update copies
[..."hello"] produces five letter strings. String spread visits Unicode code points: [..."a😀"] has two elements, while "a😀".split("") has three UTF-16 code units. Some visible symbols combine several code points, so spreading is not a general count of visible characters. A number is not iterable; [...5] throws a TypeError.
In a parameter list, function total(...nums) uses rest to gather arguments into an array. Spread in a call does the opposite: it supplies separate arguments.
For copy-based updates, [10, 20, 30].with(1, 25) gives [10, 25, 30] and .toSpliced(1, 1) gives [10, 30]. toSorted and toReversed also preserve the source. These are shallow copies, so the same inner-array sharing rule applies.
Key Takeaways
- Assignment shares an array; spread in an array literal creates a new outer array.
- Leaving out spread nests an array as one element.
- Spread can combine arrays and insert extra elements without mutation.
- A shallow copy still shares inner arrays;
structuredClonecopies these nested arrays deeply. - Call spread supplies separate arguments and is unsuitable for unbounded input sizes.
- String spread visits code points; rest parameters gather arguments.
withandtoSplicedmake changed copies.
JavaScript Loops and Arrays examples
1Trace a loop from its first check to its exit
12 steps
- 1IntroductionFollow what changes
A loop repeats a body, but its result depends on the order of checks and changes. We will follow a small total one iteration at a time, then choose a condition-based loop (while checks first, do...while after one run) and control a nested search with break and continue to leave or skip.
Keep two questions separate: what value reaches the body, and what value makes the next check fail? The final failed check is part of the control flow even though it performs no body work.
- 2ExampleSet up a running total
We want the total of
2,4and6. The counter chooses each number, while a separate accumulator retains their sum.let total = 0; for (let n = 2; n <= 6; n += 2) { total += n; }Initialization sets
nto2once. The first check,2 <= 6, succeeds. The first body run adds two to zero, leavingtotalat2. The update then changesnto4. - 3ExampleTrace the remaining checks
The next check accepts
4, so the total becomes2 + 4, or6. The update takes the counter to6, which still passesn <= 6. Adding that final value makes the total12.Afterward, the update changes
nto8. Now8 <= 6is false, and the loop stops. The body ran three times, and the condition was checked four times. No eight was added to the total. - 4ChallengeChange one endpoint
If the loop above used
n < 6instead ofn <= 6, what would its final total be, and why?---reveal---
The total would be
6: only2and4reach the body. Atn = 6, the condition is already false, so six is never added. The update still reaches six, but reaching a value in the header does not guarantee an iteration using it. - 5ExplanationLet a result decide when to stop
Suppose a batch size starts at
5and doubles until it reaches at least30. A while loop can express the unfinished work directly.let size = 5; let rounds = 0; while (size < 30) { size *= 2; rounds++; }The sizes become
10,20and40. The loop ends with three rounds, because forty is the first reached size for which another doubling is unnecessary. - 6Key InsightDecide whether a first run is required
A while loop checks before doing anything. If the starting size is already
40, the previous loop runs zero times. A do...while loop would double it once before discovering that another run is unnecessary.Use that postcheck when one run is part of the task. Counting digits by removing one digit at a time needs to count zero as a one-digit number, which makes a first body run useful.
- 7ChallengeRead a postchecked loop
What are
nandrunsafter this code?let n = 1; let runs = 0; do { n *= 3; runs++; } while (n < 8);---reveal---
nis9andrunsis2. The first body produces three and the check passes. The second produces nine and its check fails. The test happens after each multiplication, so the final value may cross the boundary. - 8ExampleSkip a value without ending the loop
This loop prints only the allowed counters.
for (let n = 1; n <= 5; n++) { if (n === 3) continue; console.log(n); }It prints
1,2,4,5. At three, continue skips the print, but the header update still moves to four. With break instead, the whole loop would stop at three and no later value would print. - 9ChallengeFind an update that gets skipped
Why does this code stop making progress at
n = 2?let n = 0; while (n < 4) { if (n === 2) continue; n++; }---reveal---
Continue jumps directly to the while condition and skips
n++. At two, every later check is true and every body run skips the update again. Increment in that branch before continuing, or use a for loop whose header performs the update. - 10ExampleFollow an inner search
For each outer value, an inner loop starts over.
for (let a = 1; a <= 3; a++) { for (let b = 1; b <= 4; b++) { if (a * b === 6) break; console.log(a, b); } }At
a = 2, reachingb = 3ends that inner loop before printing the pair. The outer loop still advances to three. An ordinary break controls the innermost loop only. - 11ChallengeEnd the whole nested search
The nested search should stop completely at its first product of six. What change achieves this, and which pair triggers it?
---reveal---
Label the outer loop
outer:and replace the break withbreak outer;. The first matching pair isa = 2,b = 3: row one has no product of six, then row two reaches it at its third column. Both loops end at that point, so row three never runs. - 12RecapRead the control path
Trace initialization once, then follow each condition, body and update in order. Count only successful entries into the body as iterations.
A while loop may skip the body entirely; a do...while loop cannot. Continue keeps the next iteration possible but can bypass a while-loop update. Break ends its loop, and a label can extend that exit to an outer search. In every case, identify the next statement execution reaches.
2Track an array and each method result
11 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionTrack two results of an edit
- 2ExampleMatch values to indexes
- 3ChallengeRead a nested schedule
- 4ExampleAdd a task and keep its return
- 5ExampleReplace a task with splice
- 6ChallengeCopy a window
- 7ExplanationSearch a position explicitly
- 8ChallengeCut and join text
- 9Key InsightKeep numeric text separate from numbers
- 10ChallengeSearch before removing
- 11RecapSeparate positions, edits and text
3Turn a loop into a useful result
10 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionChoose what the body needs
- 2ExplanationRead values directly
- 3ChallengeVisit every second position
- 4ExampleAdd a total and count long trips
- 5ExampleUse the completed total
- 6ChallengeFind an extreme without inventing zero
- 7ExampleBuild neighbor differences
- 8ChallengeKeep only increases
- 9TipRemove from the end when indexes shift
- 10RecapChoose a start for each result
4Follow a callback pipeline
15 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionLet the method manage the visits
- 2ExplanationReturn an expression or a block result
- 3ChallengeChoose a method for printed output
- 4ExampleKeep selected readings
- 5ExampleTransform the selected values
- 6ChallengeKeep valid zeros
- 7ExplanationSearch for one value or its position
- 8ChallengeRecognize a zero match
- 9Key InsightAny and all settle at different moments
- 10ExampleStart a reduction explicitly
- 11TipKeep a next accumulator on every path
- 12ChallengeTrace a filtered total
- 13ChallengeDiagnose a conversion callback
- 14ChallengeChoose all matches or one match
- 15RecapRead each returned shape
5Preserve data while ordering and formatting it
13 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionMake order and identity separate choices
- 2ExampleCheck the default order
- 3ExplanationUse the comparator sign
- 4ChallengeProtect the source order
- 5ExampleLet language decide text order
- 6ChallengeOrder numbered labels
- 7ConnectionFinish calculations before display
- 8ExampleGive the same array a second name
- 9ExampleCopy the outer list
- 10ChallengeFind a shared inner row
- 11TipPass arguments without building a huge call
- 12ChallengeCombine order, copy and formatting
- 13RecapTrace what is shared and what is returned
JavaScript Loops and Arrays practice questions
Set 1: Trace loops and read array positions10 Practice Questions
Question 1 of 10
How many times does this loop body run?
for (let i = 2; i < 7; i++) {
console.log(i);
}
Show answerHide answer
2, 3, 4, 5 and 6, giving five iterations. At 7, the condition is false before the body can run. Counting six iterations would include that failed check as though it were another body run.Question 2 of 10
["oak", "pine", "elm", "fir"].at(-2) return?Show answerHide answer
at counts backward: -1 is the last element, "fir", and -2 is "elm". "pine" is at the positive index 1; treating the negative index as an ordinary positive position selects the wrong end of the list.Question 3 of 10
What value is printed?
let n = 8;
do {
n -= 3;
} while (n > 6);
console.log(n);
Show answerHide answer
5 > 6 is then false, so execution stops. Eight would be the result of incorrectly treating the loop as a prechecked while that never enters.Question 4 of 10
What value does total hold afterward?
let total = 0;
for (let n = 3; n <= 9; n += 3) {
total += n;
}
Show answerHide answer
3, 6 and 9; the total becomes 3, then 9, then 18. The <= condition includes the final nine. A total of nine adds only the first two visited values and misses the endpoint rather than retaining all three contributions.Question 5 of 10
What numbers are printed, in order?
for (let n = 2; n <= 7; n++) {
if (n === 4) continue;
if (n === 6) break;
console.log(n);
}
Show answerHide answer
continue skips the print but still allows the counter update. Five is printed next; at six, break ends the loop before printing. The sequence ending at three confuses continue with an early exit, while a later seven would require the loop to survive the break.Question 6 of 10
What pair of values results from grid.length and grid[1][2]?
const grid = [[6, 2, 8], [9, 5, 1]];
Show answerHide answer
1 selects [9, 5, 1], and index 2 inside that row selects one. Reporting a length of three uses a row length for the outer array, mixing the two levels.Question 7 of 10
How many iterations run before this loop ends?
let size = 3;
let rounds = 0;
while (size < 20) {
size *= 2;
rounds++;
}
Show answerHide answer
6, 12 and 24. The first two still permit another iteration, but 24 < 20 is false, so the final count is three. Two iterations would stop at twelve even though the loop condition still requires more work.Question 8 of 10
How many times does count++ run?
let count = 0;
for (let a = 0; a < 4; a++) {
for (let b = a + 1; b < 4; b++) {
if (b === 3) break;
count++;
}
}
Show answerHide answer
a = 0, the increment runs at b = 1 and 2; for a = 1, it runs at b = 2. At b = 3, each inner loop breaks before incrementing, and a = 3 has no inner iterations. Six counts all distinct pairs but overlooks the early exits.Question 9 of 10
This conversion should print the same values as a counting loop that skips 2. How can it be repaired while keeping the while form?
let i = 0;
while (i < 4) {
if (i === 2) continue;
console.log(i);
i++;
}
Show answerHide answer
0, 1, 3. Replacing continue with break ends at two and loses the required later value.Question 10 of 10
[9, 2, 9].lastIndexOf(9) return?Show answerHide answer
lastIndexOf returns two. Zero is the position of the first nine and would be returned by indexOf. The method reports a position, not the matching value or the array length.Set 2: Edit arrays and build results with loops10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
What does size hold after these statements?
const tags = ["new", "open"];
const size = tags.push("done");
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
What are cut and data afterward?
const data = [4, 8, 12, 16];
const cut = data.splice(1, 2, 7);
Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
if (items.indexOf(target))?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
labels in order?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
What is the final value of count?
let count = 0;
for (const n of [11, 6, 14, 9]) {
if (n >= 10) count++;
}
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
What remains in values after this code?
const values = [3, 6, 8, 9];
for (let i = 0; i < values.length; i++) {
if (values[i] % 3 === 0) values.splice(i, 1);
}
Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
"7;12;5".split(";").join(" / ")?Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
What array is built?
const readings = [9, 4, 8, 3];
const rises = [];
for (let i = 1; i < readings.length; i++) {
const change = readings[i] - readings[i - 1];
if (change > 0) rises.push(change);
}
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
What are the length and final element of a afterward?
const a = [2, 4];
a[5] = 12;
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
0 produce the wrong result?Show answerHide answer
Save this lesson to see this answer.
Set 3: Transform, search and reduce arrays10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
What value does this reduction return?
[6, 3, 5].reduce((total, n) => total + n, 4)
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
[8, 0, 6].find(n => n < 2) return, and how should success be tested for this numeric array?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
[4, 7].map(n => { n + 3; }) return?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
What array results from this expression?
[5, 16, 9, 22].filter(n => n > 10).map(n => n - 2)
Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
What values are printed, and what is assigned to result?
const result = [2, 5, 8].forEach(n => {
if (n === 5) return;
console.log(n);
});
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
Valid readings include zero; only null means missing. What expression converts all valid readings to meters?
const km = [0, null, 1.2, 0.4];
Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
What does the code return?
[64, 40, 91].reduce((count, score) => {
if (score >= 60) return count + 1;
}, 0)
Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
70. What expression handles all input sizes?Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
What does this expression produce?
["6", "15", "4"].map(Number)
.filter(n => n % 2 === 0)
.map((n, i) => n + i)
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
Show answerHide answer
Save this lesson to see this answer.
Set 4: Sort, copy and combine results safely10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
[8, 30, 4].toSorted() return?Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
What arrays do a and c contain afterward?
const a = [6, 2];
const b = a;
const c = [...a];
b.push(9);
c[0] = 1;
Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
readings be ordered from largest to smallest while preserving its original sequence?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
"part12", "part3" and "part1" in natural numeric name order without changing parts?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
What are rows[0] and copy[1] afterward?
const rows = [[5], [8]];
const copy = [...rows];
copy[0].push(6);
copy[1] = [2];
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
[1200, 25, 4] with numbers.map(n => n.toLocaleString("de-DE")).toSorted(). How should it order and format the values to preserve numbers and display numeric ascending order?Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
What array is returned?
["lion", "ox", "bear", "ant"]
.toSorted((a, b) => a.length - b.length)
.toReversed()
Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
What does view contain afterward?
const values = [7, 2, 5];
const i = values.findIndex(n => n < 0);
values.splice(i, 1);
const view = values.toReversed();
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
What is the length of joined?
const left = [4, 6];
const right = [8, 10, 12];
const joined = [...left, right];
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
["08/02/2027", "19/01/2026", "03/12/2026"] in day/month/year form. What stored strings give chronological text order for the same dates?Show answerHide answer
Save this lesson to see this answer.
Stuck on your own question? Homework Help
Key Terms
A
Accumulator
Array
[18, 21, 19, 24] holds four daily temperature readings under one variable name.Array identity
[1, 2] === [1, 2] is false because the literals create two separate arrays.Array length
4 in a shorter array makes its length at least five, even if earlier slots are empty.Arrow function
n => n * 2 takes one number and returns a value twice as large.Ascending order
[10, 9, 1] numerically in ascending order gives [1, 9, 10].B
Break statement
break so later values are not checked after a match is stored.C
Callback
Collator
numeric: true sorts names containing digits in natural numeric sequence.Compare function
(a, b) => a - b puts smaller numeric values before larger ones.Continue statement
continue to skip printing while a for-loop counter still updates.Counter
D
Deep copy
Do...while loop
E
Early stopping
Element
["red", "green", "blue"], the string "green" is the element stored at index 1.Empty slot
new Array(3) creates three empty slots, whereas [3] creates one explicitly stored element.Entries
for (const [i, name] of names.entries()) can print numbered labels using i + 1.Every
F
Filter
t => t > 20 selects warm readings without replacing them with boolean values.Find
[3, 0, 5] returns zero, which is a successful but falsy match.FindIndex
-1.Flag
Floating-point rounding
0.1 ten times produces 0.9999999999999999, so an exact loop endpoint can be missed.For...in loop
For...of loop
for (const fruit of fruits) reads fruit names directly so the body can process each name.I
In-place sort
const ordered = scores.sort(...), ordered and scores refer to the same array.Index
colors[2] because zero-based indexing starts before index one.Index search
[3, 7, 3].lastIndexOf(3) returns 2, pointing to the last matching element.Index-based traversal
arr.length - 1 and decreases the index while it is at least zero.Infinite loop
while (n < 3) printing the same value indefinitely.Initial value
0 makes an empty sum reduction return zero instead of throwing a TypeError.Initialization
for (let i = 1; i <= 5; i++), the initialization creates i with the starting value 1.ISO date string
Iterable
5 into an array throws a TypeError.Iteration
1 through 5 with one print per body run takes five iterations.J
Join
["2026", "03", "15"].join("-") produces the date string "2026-03-15".L
List formatting
Locale
LocaleCompare
a.localeCompare(b, "en") places a before b in that comparison.Loop condition
i < 10, reaching i = 10 ends the loop before another body execution.Loop label
break outer; at a match can end both loops when the outer loop is labeled outer.M
Map
km => km * 1000 builds corresponding measurements in meters.Membership test
drinks.includes("tea") answers whether that exact lowercase string is present in the array.Method chain
Mutation
scores.push(95) mutates scores even when the variable was declared with const.N
Nested array
grid[1][0], the first index selects a row and the second selects a value within that row.Nested loop
Number formatting
1234.5 with "de-DE" produces "1.234,5", a string to display after numeric sorting.O
Off-by-one error
i <= arr.length reads one index beyond the last element in an array traversal.P
Parameter
(value, i), the second parameter receives the current element's index.Predicate
n => n !== null preserves valid zero readings while rejecting null readings.Push and pop
push and later remove that final name with pop.R
Reduce
Reduction step
count + 1 or the unchanged count according to the test.Reference
const b = a, calling b.push(4) also changes the array read through a.Rest parameter
function total(...nums), nums collects the separate arguments into one array.Return value
{ n * 2; } computes a product but fails to return it for storage.Reversal
[3, 1, 2] gives [2, 1, 3], which is not a numerically sorted sequence.S
Shallow copy
Shift and unshift
queue.shift() removes the first waiting name and moves the next name to index zero.Side effect
undefined.Slice
values.slice(1, 3) copies the values at indexes one and two into a new array.Some
Splice
days.splice(2, 0, "Wed") inserts a day at index two without removing an existing day.Split
Spread syntax
[...first, ...second] places the values from both arrays into a new outer array.Stable sort
T
Trace table
U
Update
i += 5 makes the next counter value five greater than the previous one.W
While loop
while (balance < 1500) to repeat until the target is reached.About this lesson
Make your own Study Materials
Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.