|
| 1 | +# JavaScript Loops: A Complete Guide |
| 2 | + |
| 3 | +## 1. Why Loops? |
| 4 | +Loops let you repeat an action multiple times without duplicating code. They are essential for: |
| 5 | +- Iterating over arrays, objects, strings |
| 6 | +- Processing data (filtering, transforming, aggregating) |
| 7 | +- Running asynchronous tasks sequentially |
| 8 | + |
| 9 | +--- |
| 10 | +## 2. Core Loop Types |
| 11 | +### 2.1 `for` Loop (Classic Index Loop) |
| 12 | +Best when you need the index or want fine-grained control. |
| 13 | +```js |
| 14 | +const cars = ["BMW", "Mercedes", "Toyota", "Honda"]; |
| 15 | +for (let i = 0; i < cars.length; i++) { |
| 16 | + console.log(i, cars[i]); |
| 17 | +} |
| 18 | +``` |
| 19 | +Key points: |
| 20 | +- Initialization (`let i = 0`), condition (`i < cars.length`), update (`i++`) |
| 21 | +- Can `break` or `continue` |
| 22 | +- Good for performance-sensitive code |
| 23 | + |
| 24 | +### 2.2 `while` Loop |
| 25 | +Runs while the condition is true. |
| 26 | +```js |
| 27 | +let count = 3; |
| 28 | +while (count > 0) { |
| 29 | + console.log("Count:", count); |
| 30 | + count--; |
| 31 | +} |
| 32 | +``` |
| 33 | +Use when the number of iterations isn’t known ahead of time. |
| 34 | + |
| 35 | +### 2.3 `do...while` Loop |
| 36 | +Executes **at least once** before checking the condition. |
| 37 | +```js |
| 38 | +let n = 0; |
| 39 | +do { |
| 40 | + console.log("Executed once even if condition is false initially"); |
| 41 | +} while (n > 0); |
| 42 | +``` |
| 43 | + |
| 44 | +### 2.4 `for...of` (Iterable Loop) |
| 45 | +Great for arrays, strings, Maps, Sets. |
| 46 | +```js |
| 47 | +const langs = ["JS", "Python", "Go"]; |
| 48 | +for (const lang of langs) { |
| 49 | + console.log(lang); |
| 50 | +} |
| 51 | +``` |
| 52 | +Benefits: |
| 53 | +- Cleaner than index loops |
| 54 | +- Works with any iterable (implements `[Symbol.iterator]`) |
| 55 | + |
| 56 | +### 2.5 `for...in` (Object Property Enumeration) |
| 57 | +Iterates over **enumerable keys** (including inherited ones). |
| 58 | +```js |
| 59 | +const user = { name: "Aditya", age: 23 }; |
| 60 | +for (const key in user) { |
| 61 | + console.log(key, user[key]); |
| 62 | +} |
| 63 | +``` |
| 64 | +Avoid using `for...in` on arrays (order isn’t guaranteed). Combine with `hasOwnProperty` if needed: |
| 65 | +```js |
| 66 | +for (const key in user) { |
| 67 | + if (Object.prototype.hasOwnProperty.call(user, key)) { |
| 68 | + console.log(key, user[key]); |
| 69 | + } |
| 70 | +} |
| 71 | +``` |
| 72 | + |
| 73 | +### 2.6 `Array.prototype.forEach` |
| 74 | +Higher-order method for arrays. |
| 75 | +```js |
| 76 | +const nums = [1, 2, 3]; |
| 77 | +nums.forEach((value, index) => console.log(index, value)); |
| 78 | +``` |
| 79 | +Limitations: |
| 80 | +- Can’t use `break` / `continue` |
| 81 | +- Doesn’t return a new array (use `map` if transforming) |
| 82 | + |
| 83 | +### 2.7 `for await...of` (Async Iteration) |
| 84 | +Used with async iterables or arrays of promises. |
| 85 | +```js |
| 86 | +const urls = [ |
| 87 | + fetch('https://jsonplaceholder.typicode.com/todos/1'), |
| 88 | + fetch('https://jsonplaceholder.typicode.com/todos/2') |
| 89 | +]; |
| 90 | + |
| 91 | +(async () => { |
| 92 | + for await (const res of urls) { |
| 93 | + const data = await res.json(); |
| 94 | + console.log(data.id); |
| 95 | + } |
| 96 | +})(); |
| 97 | +``` |
| 98 | + |
| 99 | +--- |
| 100 | +## 3. Comparing Loop Types |
| 101 | +| Loop | Use Case | Supports break/continue | Best For | |
| 102 | +|---------------|----------|--------------------------|----------| |
| 103 | +| for | Indexed control | Yes | Arrays with index needs | |
| 104 | +| while | Unknown end condition | Yes | Event polling, dynamic termination | |
| 105 | +| do...while | Run at least once | Yes | Menu/input loops | |
| 106 | +| for...of | Iterables | Yes | Arrays, strings, Sets, Maps | |
| 107 | +| for...in | Enumerating object keys | Yes | Plain objects (with hasOwnProperty) | |
| 108 | +| forEach | Array iteration with side-effects | No | Simple per-item processing | |
| 109 | +| for await...of| Async iterables/promises | Yes | Sequential async handling | |
| 110 | + |
| 111 | +--- |
| 112 | +## 4. Loop Control: `break`, `continue`, and Labels |
| 113 | +```js |
| 114 | +for (let i = 0; i < 5; i++) { |
| 115 | + if (i === 2) continue; // Skip 2 |
| 116 | + if (i === 4) break; // Stop loop |
| 117 | + console.log(i); |
| 118 | +} |
| 119 | +``` |
| 120 | +### Labeled Break (Avoid unless necessary) |
| 121 | +```js |
| 122 | +outer: for (let i = 0; i < 3; i++) { |
| 123 | + for (let j = 0; j < 3; j++) { |
| 124 | + if (i === 1 && j === 1) break outer; |
| 125 | + console.log(i, j); |
| 126 | + } |
| 127 | +} |
| 128 | +``` |
| 129 | + |
| 130 | +--- |
| 131 | +## 5. Iterating Objects Safely |
| 132 | +```js |
| 133 | +const person = { first: 'Ada', last: 'Lovelace' }; |
| 134 | +Object.keys(person).forEach(k => console.log(k, person[k])); |
| 135 | +Object.entries(person).forEach(([k, v]) => console.log(k, v)); |
| 136 | +``` |
| 137 | +Prefer `Object.keys/values/entries` over `for...in` when you want only own properties. |
| 138 | + |
| 139 | +--- |
| 140 | +## 6. Avoid Mutating While Iterating |
| 141 | +Bad pattern: |
| 142 | +```js |
| 143 | +const arr = [1,2,3,4]; |
| 144 | +for (let i = 0; i < arr.length; i++) { |
| 145 | + if (arr[i] % 2 === 0) arr.splice(i, 1); // Skips elements |
| 146 | +} |
| 147 | +``` |
| 148 | +Better: |
| 149 | +```js |
| 150 | +const filtered = arr.filter(x => x % 2 !== 0); |
| 151 | +``` |
| 152 | +Or iterate from end: |
| 153 | +```js |
| 154 | +for (let i = arr.length - 1; i >= 0; i--) { |
| 155 | + if (arr[i] % 2 === 0) arr.splice(i, 1); |
| 156 | +} |
| 157 | +``` |
| 158 | + |
| 159 | +--- |
| 160 | +## 7. Building Transformations Manually |
| 161 | +```js |
| 162 | +const numbers = [1,2,3,4]; |
| 163 | +// map alternative |
| 164 | +const doubled = []; |
| 165 | +for (let i = 0; i < numbers.length; i++) { |
| 166 | + doubled.push(numbers[i] * 2); |
| 167 | +} |
| 168 | +// filter alternative |
| 169 | +const evens = []; |
| 170 | +for (const n of numbers) { |
| 171 | + if (n % 2 === 0) evens.push(n); |
| 172 | +} |
| 173 | +// reduce alternative (sum) |
| 174 | +let sum = 0; |
| 175 | +for (const n of numbers) sum += n; |
| 176 | +``` |
| 177 | + |
| 178 | +--- |
| 179 | +## 8. Performance Notes |
| 180 | +- `for` with cached length is slightly faster in tight loops: |
| 181 | +```js |
| 182 | +for (let i = 0, len = arr.length; i < len; i++) {} |
| 183 | +``` |
| 184 | +- Avoid heavy synchronous loops in the UI thread (they block rendering) |
| 185 | +- For large data, consider batching with `setTimeout` / `requestIdleCallback` |
| 186 | + |
| 187 | +--- |
| 188 | +## 9. Async Pitfalls in Loops |
| 189 | +### Using `var` inside loops with async callbacks |
| 190 | +```js |
| 191 | +for (var i = 1; i <= 3; i++) { |
| 192 | + setTimeout(() => console.log(i), 0); // 4,4,4 |
| 193 | +} |
| 194 | +``` |
| 195 | +Fix with `let` (block scoping) or IIFE: |
| 196 | +```js |
| 197 | +for (let i = 1; i <= 3; i++) { |
| 198 | + setTimeout(() => console.log(i), 0); // 1,2,3 |
| 199 | +} |
| 200 | +``` |
| 201 | +Sequential async with `for...of`: |
| 202 | +```js |
| 203 | +async function process(ids) { |
| 204 | + for (const id of ids) { |
| 205 | + await doAsync(id); // waits each turn |
| 206 | + } |
| 207 | +} |
| 208 | +``` |
| 209 | +Parallel async: |
| 210 | +```js |
| 211 | +await Promise.all(ids.map(doAsync)); |
| 212 | +``` |
| 213 | + |
| 214 | +--- |
| 215 | +## 10. When to Use What |
| 216 | +| Need | Pick | |
| 217 | +|------|------| |
| 218 | +| Index + control | for | |
| 219 | +| Unknown iteration count | while | |
| 220 | +| Run at least once | do...while | |
| 221 | +| Clean element iteration | for...of | |
| 222 | +| Own object keys | Object.keys + forEach | |
| 223 | +| Transform / filter / accumulate | map / filter / reduce | |
| 224 | +| Async sequential | for await...of or for...of with await | |
| 225 | +| Async parallel | Promise.all | |
| 226 | + |
| 227 | +--- |
| 228 | +## 11. Practical Examples |
| 229 | +### Summing Nested Arrays |
| 230 | +```js |
| 231 | +const matrix = [[1,2],[3,4],[5,6]]; |
| 232 | +let total = 0; |
| 233 | +for (const row of matrix) { |
| 234 | + for (const value of row) total += value; |
| 235 | +} |
| 236 | +console.log(total); // 21 |
| 237 | +``` |
| 238 | +### Counting Frequencies |
| 239 | +```js |
| 240 | +const letters = ['a','b','a','c','b','a']; |
| 241 | +const freq = {}; |
| 242 | +for (const ch of letters) { |
| 243 | + freq[ch] = (freq[ch] || 0) + 1; |
| 244 | +} |
| 245 | +console.log(freq); // { a:3, b:2, c:1 } |
| 246 | +``` |
| 247 | +### Flatten One Level |
| 248 | +```js |
| 249 | +const nested = [1,[2,3],[4,5]]; |
| 250 | +const flat = []; |
| 251 | +for (const item of nested) { |
| 252 | + if (Array.isArray(item)) { |
| 253 | + for (const inner of item) flat.push(inner); |
| 254 | + } else flat.push(item); |
| 255 | +} |
| 256 | +console.log(flat); // [1,2,3,4,5] |
| 257 | +``` |
| 258 | + |
| 259 | +--- |
| 260 | +## 12. Edge Cases |
| 261 | +- Mutating `length` during a loop affects iteration. |
| 262 | +- `forEach` skips holes in sparse arrays; `for` does not if index exists. |
| 263 | +- `for...in` order is not guaranteed for integer-like keys. |
| 264 | +- `break` in `try/finally` still executes `finally`. |
| 265 | + |
| 266 | +--- |
| 267 | +## 13. Mini Cheatsheet |
| 268 | +| Goal | Preferred | Alternate | |
| 269 | +|------|-----------|-----------| |
| 270 | +| Iterate array values | for...of | for / forEach | |
| 271 | +| Need index + value | for | arr.entries() + for...of | |
| 272 | +| Iterate string chars | for...of | classic for | |
| 273 | +| Object own keys | Object.keys(obj) | for...in + hasOwnProperty | |
| 274 | +| Parallel async tasks | Promise.all | forEach + async (avoid) | |
| 275 | +| Sequential async tasks | for...of + await | reduce chain | |
| 276 | + |
| 277 | +--- |
| 278 | +## 14. Practice Exercises |
| 279 | +1. Reverse an array in-place using a `for` loop. |
| 280 | +2. Write a loop to find the second largest number. |
| 281 | +3. Use `for...of` to sum only even numbers in an array. |
| 282 | +4. Implement a manual version of `Array.prototype.filter` using a loop. |
| 283 | +5. Loop through a string and count vowels. |
| 284 | + |
| 285 | +--- |
| 286 | +## 15. Summary |
| 287 | +Mastering loops means knowing not just the syntax, but **which tool fits which scenario**. Start with readable constructs (`for...of`, array methods) and drop to lower-level loops (`for`, `while`) when you need control or performance. |
| 288 | + |
| 289 | +Happy looping! |
0 commit comments