From 7858327344a4ba0c354b10b34f301c3d77605beb Mon Sep 17 00:00:00 2001 From: wbamberg Date: Sun, 28 Nov 2021 16:17:45 -0800 Subject: [PATCH] JS Learning Area updates: looping code (#10645) --- .../building_blocks/looping_code/index.md | 564 ++++++++++++------ .../looping_code/loop_js-02-farm.png | Bin 41232 -> 0 bytes .../test_your_skills_colon__loops/index.md | 4 +- 3 files changed, 369 insertions(+), 199 deletions(-) delete mode 100644 files/en-us/learn/javascript/building_blocks/looping_code/loop_js-02-farm.png diff --git a/files/en-us/learn/javascript/building_blocks/looping_code/index.md b/files/en-us/learn/javascript/building_blocks/looping_code/index.md index a676723ca4d9e7e..0b8dc239c61b834 100644 --- a/files/en-us/learn/javascript/building_blocks/looping_code/index.md +++ b/files/en-us/learn/javascript/building_blocks/looping_code/index.md @@ -38,114 +38,75 @@ Programming languages are very useful for rapidly completing repetitive tasks, f -## Keep me in the loop +## Why are loops useful? -Loops, loops, loops. As well as being associated with [popular breakfast cereals](https://en.wikipedia.org/wiki/Froot_Loops), [roller coasters](https://en.wikipedia.org/wiki/Vertical_loop), and [musical production](), they are also a critical concept in programming. Programming loops are all to do with doing the same thing over and over again, which is termed **iteration** in programming speak. +Loops are all about doing the same thing over and over again. Often, the code will be slightly different each time round the loop, or the same code will run but with different variables. -Let's consider the case of a farmer who is making sure he has enough food to feed his family for the week. He might use the following loop to achieve this: +### Looping code example -![](loop_js-02-farm.png) +Suppose we wanted to draw 100 random circles on a {{htmlelement("canvas")}} element (press the _Update_ button to run the example again and again to see different random sets): -A loop usually has one or more of the following features: - -- A **counter**, which is initialized with a certain value — this is the starting point of the loop ("Start: I have no food", above). -- A **condition**, which is a true/false test to determine whether the loop continues to run, or stops — usually when the counter reaches a certain value. This is illustrated by "Have I got enough food?" above. Let's say he needs 10 portions of food to feed his family. -- An **iterator**, which generally increments the counter by a small amount on each successive loop until the condition is no longer `true`. We haven't explicitly illustrated this above, but we could think about the farmer being able to collect say 2 portions of food per hour. After each hour, the amount of food he has collected is incremented by two, and he checks whether he has enough food. If he has reached 10 portions (the point where the condition is no longer true, so the loop exits), he can stop collecting and go home. +```html hidden + + +``` -In {{glossary("pseudocode")}}, this would look something like the following: +```css hidden +html { + width: 100%; + height: inherit; + background: #ddd; +} - loop(food = 0; foodNeeded = 10) { - if (food >= foodNeeded) { - exit loop; - // We have enough food; let's go home - } else { - food += 2; // Spend an hour collecting 2 more food - // loop will then run again - } - } +canvas { + display: block; +} -So the amount of food needed is set at 10, and the amount the farmer currently has is set at 0. In each iteration of the loop, we check whether the amount of food the farmer has is larger or equal to the amount he needs. If so, we can exit the loop. If not, the farmer spends an hour collecting two portions of food and the loop runs again. +body { + margin: 0; +} -### Why bother? +button { + position: absolute; + top: 5px; + left: 5px; +} +``` -At this point, you probably understand the high-level concepts behind loops, but you are probably thinking "OK, great, but how does this help me write better JavaScript code?" As we said earlier, **loops are all to do with doing the same thing over and over again**, which is great for **rapidly completing repetitive tasks**. +{{ EmbedLiveSample('Looping_code_example', '100%', 400) }} -Often, the code will be slightly different on each successive iteration of the loop, which means that you can complete a whole load of tasks that are similar but slightly different; if you've got a lot of different calculations to do, you want to do each different one, not the same one over and over again! +Here's the JavaScript code that implements this example: -#### Looping code example -Let's look at an example to illustrate why loops are such a good thing. Let's say we wanted to draw 100 random circles on a {{htmlelement("canvas")}} element (press the _Update_ button to run the example again and again to see different random sets): +```js +const btn = document.querySelector('button'); +const canvas = document.querySelector('canvas'); +const ctx = canvas.getContext('2d'); -```html hidden - - - - - Random canvas circles - - - - - - - - - +function draw() { + ctx.clearRect(0,0,WIDTH,HEIGHT); + for (let i = 0; i < 100; i++) { + ctx.beginPath(); + ctx.fillStyle = 'rgba(255,0,0,0.5)'; + ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); + ctx.fill(); + } +} - - +btn.addEventListener('click',draw); ``` -{{ EmbedLiveSample('Looping_code_example', '100%', 400) }} - -#### With and without a loop +### With and without a loop You don't have to understand all the code for now, but let's look at the part of the code that actually draws the 100 circles: @@ -161,7 +122,9 @@ for (let i = 0; i < 100; i++) { - `random(x)`, defined earlier in the code, returns a whole number between `0` and `x-1`. - `WIDTH` and `HEIGHT` are the width and height of the inner browser window. -You should get the basic idea — we are using a loop to run 100 iterations of this code, each one of which draws a circle in a random position on the page. The amount of code needed would be the same whether we were drawing 100 circles, 1000, or 10,000. Only one number has to change. +You should get the basic idea — we are using a loop to run 100 iterations of this code, each one of which draws a circle in a random position on the page. +The amount of code needed would be the same whether we were drawing 100 circles, 1000, or 10,000. +Only one number has to change. If we weren't using a loop here, we'd have to repeat the following code for every circle we wanted to draw: @@ -172,110 +135,253 @@ ctx.arc(random(WIDTH), random(HEIGHT), random(50), 0, 2 * Math.PI); ctx.fill(); ``` -This would get very boring and difficult to maintain very quickly. Loops really are the best. +This would get very boring and difficult to maintain. -## The standard for loop +## Looping through a collection -Let's start exploring some specific loop constructs. The first, which you'll use most of the time, is the [for](/en-US/docs/Web/JavaScript/Reference/Statements/for) loop. This has the following syntax: +Most of the time when you use a loop, you will have a collection of items and want to do something with every item. - for (initializer; condition; final-expression) { - // code to run - } +One type of collection is the {{jsxref("Array")}}, which we met in the [Arrays](/en-US/docs/Learn/JavaScript/First_steps/Arrays) chapter of this course. +But there are other collections in JavaScript as well, including {{jsxref("Set")}} and {{jsxref("Map")}}. + +### The for...of loop + +The basic tool for looping through a collection is the {{jsxref("statements/for...of","for...of")}} loop: + +```js +const cats = ['Leopard', 'Serval', 'Jaguar', 'Tiger', 'Caracal', 'Lion']; + +for (const cat of cats) { + console.log(cat); +} +``` + +In this example, `for (const cat of cats)` says: + +1. Given the collection `cats`, get the first item in the collection. +2. Assign it to the variable `cat` and then run the code between the curly brackets `{}`. +3. Get the next item, and repeat (2) until you've reached the end of the collection. + +### map() and filter() + +JavaScript also has more specialized loops for collections, and we'll mention two of them here. + +You can use `map()` to do something to each item in a collection and create a new collection containing the changed items: + +```js +function toUpper(string) { + return string.toUpperCase(); +} + +const cats = ['Leopard', 'Serval', 'Jaguar', 'Tiger', 'Caracal', 'Lion']; + +const upperCats = cats.map(toUpper); + +console.log(upperCats); +// [ "LEOPARD", "SERVAL", "JAGUAR", "TIGER", "CARACAL", "LION" ] +``` + +Here we pass a function into {{jsxref("Array.prototype.map()","cats.map()")}}, and `map()` calls the function once for each item in the array, passing in the item. It then adds the return value from each function call to a new array, and finally returns the new array. In this case the function we provide converts the item to uppercase, so the resulting array contains all our cats in uppercase: + +``` +[ "LEOPARD", "SERVAL", "JAGUAR", "TIGER", "CARACAL", "LION" ] +``` + +You can use {{jsxref("Array.prototype.filter()","filter()")}} to test each item in a collection, and create a new collection containing only items that match: + +```js +function lCat(cat) { + return cat.startsWith('L'); +} + +const cats = ['Leopard', 'Serval', 'Jaguar', 'Tiger', 'Caracal', 'Lion']; + +const filtered = cats.filter(lCat); + +console.log(filtered); +// [ "Leopard", "Lion" ] +``` + +This looks a lot like `map()`, except the function we pass in returns a [boolean](/en-US/docs/Learn/JavaScript/First_steps/Variables#booleans): if it returns `true`, then the item is included in the new array. +Our function tests that the item starts with the letter "L", so the result is an array containing only cats whose names start with "L": + +``` +[ "Leopard", "Lion" ] +``` +Note that `map()` and `filter()` are both often used with _function expressions_, which we will learn about in the [Functions](/en-US/docs/Learn/JavaScript/Building_blocks/Functions) module. +Using function expressions we could rewrite the example above to be much more compact: + +```js +const cats = ['Leopard', 'Serval', 'Jaguar', 'Tiger', 'Caracal', 'Lion']; + +const filtered = cats.filter((cat) => cat.startsWith('L')); +console.log(filtered); +// [ "Leopard", "Lion" ] +``` + +## The standard for loop + +In the "drawing circles" example above, you don't have a collection of items to loop through: you really just want to run the same code 100 times. +In a case like that you should use the {{jsxref("statements/for","for")}} loop. +This has the following syntax: + +```js +for (initializer; condition; final-expression) { + // code to run +} +``` Here we have: -1. The keyword `for`, followed by some parentheses. -2. Inside the parentheses we have three items, separated by semi-colons: +1. The keyword `for`, followed by some parentheses. +2. Inside the parentheses we have three items, separated by semi-colons: - 1. An **initializer** — this is usually a variable set to a number, which is incremented to count the number of times the loop has run. It is also sometimes referred to as a **counter variable**. - 2. A **condition** — as mentioned before, this defines when the loop should stop looping. This is generally an expression featuring a comparison operator, a test to see if the exit condition has been met. - 3. A **final-expression** — this is always evaluated (or run) each time the loop has gone through a full iteration. It usually serves to increment (or in some cases decrement) the counter variable, to bring it closer to the point where the condition is no longer `true`. + 1. An **initializer** — this is usually a variable set to a number, which is incremented to count the number of times the loop has run. + It is also sometimes referred to as a **counter variable**. + 3. A **condition** — this defines when the loop should stop looping. + This is generally an expression featuring a comparison operator, a test to see if the exit condition has been met. + 5. A **final-expression** — this is always evaluated (or run) each time the loop has gone through a full iteration. + It usually serves to increment (or in some cases decrement) the counter variable, to bring it closer to the point where the condition is no longer `true`. -3. Some curly braces that contain a block of code — this code will be run each time the loop iterates. +3. Some curly braces that contain a block of code — this code will be run each time the loop iterates. -### Listing my cats +### Calculating squares Let's look at a real example so we can visualize what these do more clearly. ```html hidden -

+ + +

 ```
 
 ```js
-const cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin'];
-let info = 'My cats are called ';
-const para = document.querySelector('p');
+const results = document.querySelector('#results');
 
-for (let i = 0; i < cats.length; i++) {
-  info += cats[i] + ', ';
+function calculate() {
+  for (let i = 1; i < 10; i++) {
+    const newResult = `${i} x ${i} = ${i * i}`;
+    results.textContent += `${newResult}\n`;
+  }
+  results.textContent += '\n...finished!';
 }
 
-para.textContent = info;
+const calculateBtn = document.querySelector('#calculate');
+const clearBtn = document.querySelector('#clear');
+
+calculateBtn.addEventListener('click', calculate);
+clearBtn.addEventListener('click', () => results.textContent = '');
+
 ```
 
 This gives us the following output:
 
-{{ EmbedLiveSample('Listing_my_cats', '100%', 80) }}
+{{ EmbedLiveSample('Calculating squares', '100%', 250) }}
 
-> **Note:** You can find this [example code on GitHub](https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for.html) too (also [see it running live](https://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for.html)).
+This code calculates squares for the numbers from 1 to 9, and writes out the result. The core of the code is the `for` loop that performs the calculation.
 
-This shows a loop is used to iterate over the items in an array and do something with each of them — a very common pattern in JavaScript. Here:
+Let's break down the `for (let i = 1; i < 10; i++)` line into its three pieces:
 
-1.  The counter variable (sometimes known as an initializer or an iteration variable), `i`, starts at `0` (`let i = 0`).
-2.  The loop has been told to run until `i` is no longer smaller than the length of the `cats` array. This is important — the condition is the condition under which the loop will still run. So in this case, while `i < cats.length` is still true, the loop will still run.
-3.  Inside the loop, we concatenate the current loop item (`cats[i]` , which is `cats[whatever i is at the time]`) along with a comma and space, onto the end of the `info` variable. So:
+1. `let i = 1`: the counter variable, `i`, starts at `1`. Note that we have to use `let` for the counter, because we're reassigning it each time we go round the loop.
+2. `i < 10`: keep going round the loop for as long as `i` is smaller than `10`.
+3. `i++`: add one to `i` each time round the loop.
 
-    1.  During the first run, `i = 0`, therefore `cats[0] + ', '` (which is equal to `Bill, `) will be concatenated onto `info`.
-    2.  During the second run, `i = 1`, so `cats[1] + ', '` (which is equal to `Jeff, `) will be concatenated onto `info`.
-    3.  And so on. After each time the loop has run, 1 will be added to `i` (`i++`), then the process will start again.
+Inside the loop, we calculate the square of the current value of `i`, that is: `i * i`. We create a string expressing the calculation we made and the result, and add this string to the output text. We also add `\n`, so the next string we add will begin on a new line. So:
 
-4.  When `i` becomes equal to `cats.length` (in this case, 5), the loop will stop, and the browser will move on to the next bit of code below the loop.
+1. During the first run, `i = 1`, so we will add `1 x 1 = 1`.
+2. During the second run, `i = 2`, so we will add `2 x 2 = 4`.
+3. ...and so on.
+4. When `i` becomes equal to `10` we will stop running the loop and move straight to the next bit of code below the loop, printing out the `...finished!` message.
 
-> **Note:** We have made the condition `i < cats.length`, not `i <= cats.length`, because computers count from 0, not 1 — we are starting `i` at `0`, and going up to `i = 4` (the index of the last array item). `cats.length` returns 5, as there are 5 items in the array, but we don't want to get up to `i = 5`, as that would return `undefined` for the last item (there is no array item with an index of 5). So, therefore, we want to go up to 1 less than `cats.length` (`i <`), not the same as `cats.length` (`i <=`).
+### Looping through collections with a for loop
 
-> **Note:** A common mistake with conditions is making them use "equal to" (`===`) rather than say "less than or equal to" (`<=`). If we wanted to run our loop up to `i = 5`, the exit condition would need to be `i <= cats.length`. If we set it to `i === cats.length`, the loop would not run at all because `i` is not equal to `5` on the first loop iteration, so it would stop immediately.
+You can use a `for` loop to iterate through a collection, instead of a `for...of` loop.
 
-### Handling the last cat
+Let's look again at our `for...of` example above:
 
-One small problem we are left with is that the final output sentence isn't very well-formed:
+```js
+const cats = ['Leopard', 'Serval', 'Jaguar', 'Tiger', 'Caracal', 'Lion'];
 
-> My cats are called Bill, Jeff, Pete, Biggles, Jasmin,
+for (const cat of cats) {
+  console.log(cat);
+}
+```
 
-Ideally, we want to change the concatenation on the final loop iteration so that we haven't got a comma on the end of the sentence. Well, no problem — we can quite happily insert a conditional inside our for loop to handle this special case:
+We could rewrite that code like this:
 
-```html hidden
-  

+```js +const cats = ['Leopard', 'Serval', 'Jaguar', 'Tiger', 'Caracal', 'Lion']; + +for (let i = 0; i < cats.length; i++) { + console.log(cats[i]); +} ``` +In this loop we're starting `i` at `0`, and stopping when `i` reaches the length of the array. +Then inside the loop we're using `i` to access each item in the array in turn. + +This works just fine, and in early versions of JavaScript, `for...of` didn't exist, so this was the standard way to iterate through an array. +However, it offers more chances to introduce bugs into your code. For example: + +* you might start `i` at `1`, forgetting that the first array index is zero, not 1. +* you might stop at `i <= cats.length`, forgetting that the last array index is at `length - 1`. + +For reasons like this, it's usually best to use `for...of` if you can. + +Sometimes you still need to use a `for` loop to iterate through an array. +For example, in the code below we want to log a message listing our cats: + ```js -const cats = ['Bill', 'Jeff', 'Pete', 'Biggles', 'Jasmin']; -let info = 'My cats are called '; -const para = document.querySelector('p'); +const cats = ['Pete', 'Biggles', 'Jasmin']; -for (let i = 0; i < cats.length; i++) { - if (i === cats.length - 1) { - info += 'and ' + cats[i] + '.'; - } else { - info += cats[i] + ', '; - } +let myFavoriteCats = 'My cats are called '; + +for (const cat of cats) { + myFavoriteCats = `${myFavoriteCats}${cat}, ` } -para.textContent = info; +console.log(myFavoriteCats); // "My cats are called Pete, Biggles, Jasmin, " +``` + +The final output sentence isn't very well-formed: + +``` +My cats are called Pete, Biggles, Jasmin, ``` -{{ EmbedLiveSample('Handling_the_last_cat', '100%', 80) }} +We'd prefer it to handle the last cat differently, like this: -> **Note:** You can find this [example code on GitHub](https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/basic-for-improved.html) too (also [see it running live](https://mdn.github.io/learning-area/javascript/building-blocks/loops/basic-for-improved.html)). +``` +My cats are called Pete, Biggles, and Jasmin. +``` -> **Warning:** With for — as with all loops — you must make sure that the initializer is incremented or, depending on the case, decremented, so that it eventually reaches the point where the condition is not true. If not, the loop will go on forever, and either the browser will force it to stop, or it will crash. This is called an **infinite loop**. +But to do this we need to know when we are on the final loop iteration, and to do that we can use a `for` loop and examine the value of `i`: + +```js +const cats = ['Pete', 'Biggles', 'Jasmin']; + +let myFavoriteCats = 'My cats are called '; + +for (let i = 0; i < cats.length; i++) { + if (i === cats.length - 1) { // We are at the end of the array + myFavoriteCats = `${myFavoriteCats}and ${cats[i]}.` + } else { + myFavoriteCats = `${myFavoriteCats}${cats[i]}, ` + } +} + +console.log(myFavoriteCats); // "My cats are called Pete, Biggles, and Jasmin." +``` ## Exiting loops with break -If you want to exit a loop before all the iterations have been completed, you can use the [break](/en-US/docs/Web/JavaScript/Reference/Statements/break) statement. We already met this in the previous article when we looked at [switch statements](/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#switch_statements) — when a case is met in a switch statement that matches the input expression, the `break` statement immediately exits the switch statement and moves on to the code after it. +If you want to exit a loop before all the iterations have been completed, you can use the [break](/en-US/docs/Web/JavaScript/Reference/Statements/break) statement. +We already met this in the previous article when we looked at [switch statements](/en-US/docs/Learn/JavaScript/Building_blocks/conditionals#switch_statements) — when a case is met in a switch statement that matches the input expression, the `break` statement immediately exits the switch statement and moves on to the code after it. It's the same with loops — a `break` statement will immediately exit the loop and make the browser move on to any code that follows it. -Say we wanted to search through an array of contacts and telephone numbers and return just the number we wanted to find? First, some simple HTML — a text {{htmlelement("input")}} allowing us to enter a name to search for, a {{htmlelement("button")}} element to submit a search, and a {{htmlelement("p")}} element to display the results in: +Say we wanted to search through an array of contacts and telephone numbers and return just the number we wanted to find? +First, some simple HTML — a text {{htmlelement("input")}} allowing us to enter a name to search for, a {{htmlelement("button")}} element to submit a search, and a {{htmlelement("p")}} element to display the results in: ```html @@ -294,39 +400,43 @@ const input = document.querySelector('input'); const btn = document.querySelector('button'); btn.addEventListener('click', function() { - let searchName = input.value.toLowerCase(); + const searchName = input.value.toLowerCase(); input.value = ''; input.focus(); - for (let i = 0; i < contacts.length; i++) { - let splitContact = contacts[i].split(':'); + para.textContent = ''; + for (const contact of contacts) { + const splitContact = contact.split(':'); if (splitContact[0].toLowerCase() === searchName) { para.textContent = splitContact[0] + '\'s number is ' + splitContact[1] + '.'; break; - } else if (i === contacts.length-1) { - para.textContent = 'Contact not found.'; } } + if (para.textContent === '') { + para.textContent = 'Contact not found.'; + } }); ``` {{ EmbedLiveSample('Exiting_loops_with_break', '100%', 100) }} -1. First of all, we have some variable definitions — we have an array of contact information, with each item being a string containing a name and phone number separated by a colon. -2. Next, we attach an event listener to the button (`btn`) so that when it is pressed some code is run to perform the search and return the results. -3. We store the value entered into the text input in a variable called `searchName`, before then emptying the text input and focusing it again, ready for the next search. Note that we also run the [`toLowerCase()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) method on the string, so that searches will be case-insensitive. -4. Now on to the interesting part, the for loop: +1. First of all, we have some variable definitions — we have an array of contact information, with each item being a string containing a name and phone number separated by a colon. +2. Next, we attach an event listener to the button (`btn`) so that when it is pressed some code is run to perform the search and return the results. +3. We store the value entered into the text input in a variable called `searchName`, before then emptying the text input and focusing it again, ready for the next search. + Note that we also run the [`toLowerCase()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) method on the string, so that searches will be case-insensitive. +5. Now on to the interesting part, the `for...of` loop: - 1. We start the counter at `0`, run the loop until the counter is no longer less than `contacts.length`, and increment `i` by 1 after each iteration of the loop. - 2. Inside the loop, we first split the current contact (`contacts[i]`) at the colon character, and store the resulting two values in an array called `splitContact`. - 3. We then use a conditional statement to test whether `splitContact[0]` (the contact's name, again lower-cased with [`toLowerCase()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase)) is equal to the inputted `searchName`. If it is, we enter a string into the paragraph to report what the contact's number is, and use `break` to end the loop. + 1. Inside the loop, we first split the current contact at the colon character, and store the resulting two values in an array called `splitContact`. + 2. We then use a conditional statement to test whether `splitContact[0]` (the contact's name, again lower-cased with [`toLowerCase()`](/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase)) is equal to the inputted `searchName`. + If it is, we enter a string into the paragraph to report what the contact's number is, and use `break` to end the loop. -5. After `(contacts.length-1)` iterations, if the contact name does not match the entered search the paragraph text is set to "Contact not found.", and the loop continues looping until the condition is no longer true. +4. After the loop, we check whether we set a contact, and if not we set the paragraph text to "Contact not found.". > **Note:** You can view the [full source code on GitHub](https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/contact-search.html) too (also [see it running live](https://mdn.github.io/learning-area/javascript/building-blocks/loops/contact-search.html)). ## Skipping iterations with continue -The [continue](/en-US/docs/Web/JavaScript/Reference/Statements/continue) statement works in a similar manner to `break`, but instead of breaking out of the loop entirely, it skips to the next iteration of the loop. Let's look at another example that takes a number as an input, and returns only the numbers that are squares of integers (whole numbers). +The [continue](/en-US/docs/Web/JavaScript/Reference/Statements/continue) statement works in a similar manner to `break`, but instead of breaking out of the loop entirely, it skips to the next iteration of the loop. +Let's look at another example that takes a number as an input, and returns only the numbers that are squares of integers (whole numbers). The HTML is basically the same as the last example — a simple text input, and a paragraph for output. @@ -364,10 +474,10 @@ Here's the output: {{ EmbedLiveSample('Skipping_iterations_with_continue', '100%', 100) }} -1. In this case, the input should be a number (`num`). The `for` loop is given a counter starting at 1 (as we are not interested in 0 in this case), an exit condition that says the loop will stop when the counter becomes bigger than the input `num`, and an iterator that adds 1 to the counter each time. -2. Inside the loop, we find the square root of each number using [Math.sqrt(i)](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt), then check whether the square root is an integer by testing whether it is the same as itself when it has been rounded down to the nearest integer (this is what [Math.floor()](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor) does to the number it is passed). -3. If the square root and the rounded down square root do not equal one another (`!==`), it means that the square root is not an integer, so we are not interested in it. In such a case, we use the `continue` statement to skip on to the next loop iteration without recording the number anywhere. -4. If the square root is an integer, we skip past the `if` block entirely, so the `continue` statement is not executed; instead, we concatenate the current `i` value plus a space on to the end of the paragraph content. +1. In this case, the input should be a number (`num`). The `for` loop is given a counter starting at 1 (as we are not interested in 0 in this case), an exit condition that says the loop will stop when the counter becomes bigger than the input `num`, and an iterator that adds 1 to the counter each time. +2. Inside the loop, we find the square root of each number using [Math.sqrt(i)](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sqrt), then check whether the square root is an integer by testing whether it is the same as itself when it has been rounded down to the nearest integer (this is what [Math.floor()](/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/floor) does to the number it is passed). +3. If the square root and the rounded down square root do not equal one another (`!==`), it means that the square root is not an integer, so we are not interested in it. In such a case, we use the `continue` statement to skip on to the next loop iteration without recording the number anywhere. +4. If the square root is an integer, we skip past the `if` block entirely, so the `continue` statement is not executed; instead, we concatenate the current `i` value plus a space on to the end of the paragraph content. > **Note:** You can view the [full source code on GitHub](https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/integer-squares.html) too (also [see it running live](https://mdn.github.io/learning-area/javascript/building-blocks/loops/integer-squares.html)). @@ -384,24 +494,33 @@ First, let's have a look at the [while](/en-US/docs/Web/JavaScript/Reference/Sta final-expression } -This works in a very similar way to the `for` loop, except that the initializer variable is set before the loop, and the final-expression is included inside the loop after the code to run, rather than these two items being included inside the parentheses. The condition is included inside the parentheses, which are preceded by the `while` keyword rather than `for`. +This works in a very similar way to the `for` loop, except that the initializer variable is set before the loop, and the final-expression is included inside the loop after the code to run, rather than these two items being included inside the parentheses. +The condition is included inside the parentheses, which are preceded by the `while` keyword rather than `for`. -The same three items are still present, and they are still defined in the same order as they are in the for loop. This is because you must have an initializer defined before you can check whether or not the condition is true. The final-expression is then run after the code inside the loop has run (an iteration has been completed), which will only happen if the condition is still true. +The same three items are still present, and they are still defined in the same order as they are in the for loop. +This is because you must have an initializer defined before you can check whether or not the condition is true. +The final-expression is then run after the code inside the loop has run (an iteration has been completed), which will only happen if the condition is still true. Let's have a look again at our cats list example, but rewritten to use a while loop: ```js +const cats = ['Pete', 'Biggles', 'Jasmin']; + +let myFavoriteCats = 'My cats are called '; + let i = 0; while (i < cats.length) { if (i === cats.length - 1) { - info += 'and ' + cats[i] + '.'; + myFavoriteCats += `and ${cats[i]}.`; } else { - info += cats[i] + ', '; + myFavoriteCats += `${cats[i]}, `; } i++; } + +console.log(myFavoriteCats); // "My cats are called Pete, Biggles, and Jasmin." ``` > **Note:** This still works just the same as expected — have a look at it [running live on GitHub](https://mdn.github.io/learning-area/javascript/building-blocks/loops/while.html) (also view the [full source code](https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/while.html)). @@ -417,34 +536,43 @@ The [do...while](/en-US/docs/Web/JavaScript/Reference/Statements/do...while) loo In this case, the initializer again comes first, before the loop starts. The keyword directly precedes the curly braces containing the code to run and the final expression. -The differentiator here is that the condition comes after everything else, wrapped in parentheses and preceded by a `while` keyword. In a `do...while` loop, the code inside the curly braces is always run once before the check is made to see if it should be executed again (in while and for, the check comes first, so the code might never be executed). +The main difference between a `do...while` loop and a `while` loop is that _the code inside a `do...while` loop is always executed at least once_. That's because the condition comes after the code inside the loop. So we always run that code, then check to see if we need to run it again. In `while` and `for` loops, the check comes first, so the code might never be executed. Let's rewrite our cat listing example again to use a `do...while` loop: ```js +const cats = ['Pete', 'Biggles', 'Jasmin']; + +let myFavoriteCats = 'My cats are called '; + let i = 0; do { if (i === cats.length - 1) { - info += 'and ' + cats[i] + '.'; + myFavoriteCats += `and ${cats[i]}.`; } else { - info += cats[i] + ', '; + myFavoriteCats += `${cats[i]}, `; } i++; } while (i < cats.length); + +console.log(myFavoriteCats); // "My cats are called Pete, Biggles, and Jasmin." ``` > **Note:** Again, this works just the same as expected — have a look at it [running live on GitHub](https://mdn.github.io/learning-area/javascript/building-blocks/loops/do-while.html) (also view the [full source code](https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/loops/do-while.html)). -> **Warning:** With while and do...while — as with all loops — you must make sure that the initializer is incremented or, depending on the case, decremented, so the condition eventually becomes false. If not, the loop will go on forever, and either the browser will force it to stop, or it will crash. This is called an **infinite loop**. +> **Warning:** With while and do...while — as with all loops — you must make sure that the initializer is incremented or, depending on the case, decremented, so the condition eventually becomes false. +> If not, the loop will go on forever, and either the browser will force it to stop, or it will crash. This is called an **infinite loop**. ## Active learning: Launch countdown -In this exercise, we want you to print out a simple launch countdown to the output box, from 10 down to Blastoff. Specifically, we want you to: +In this exercise, we want you to print out a simple launch countdown to the output box, from 10 down to Blastoff. +Specifically, we want you to: - Loop from 10 down to 0. We've provided you with an initializer — `let i = 10;`. -- For each iteration, create a new paragraph and append it to the output `
`, which we've selected using `const output = document.querySelector('.output');`. In comments, we've provided you with three code lines that need to be used somewhere inside the loop: +- For each iteration, create a new paragraph and append it to the output `
`, which we've selected using `const output = document.querySelector('.output');`. + In comments, we've provided you with three code lines that need to be used somewhere inside the loop: - `const para = document.createElement('p');` — creates a new paragraph. - `output.appendChild(para);` — appends the paragraph to the output `
`. @@ -460,7 +588,8 @@ In this exercise, we want you to print out a simple launch countdown to the outp > **Note:** If you start typing the loop (for example (while(i>=0)), the browser might stuck because you have not yet entered the end condition. So be careful with this. You can start writing your code in a comment to deal with this issue and remove the comment after you finish. -If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution. +If you make a mistake, you can always reset the example with the "Reset" button. +If you get really stuck, press "Show solution" to see a solution. ```html hidden

Live output

@@ -596,7 +725,7 @@ In this exercise, we want you to take a list of names stored in an array and put Specifically, we want you to: -- Write a loop that will iterate from 0 to the length of the `people` array. You'll need to start with an initializer of  `let i = 0;`, but what condition do you need? +- Write a loop that will iterate through the `people` array. - During each loop iteration, check if the current array item is equal to "Phil" or "Lola" using a conditional statement: - If it is, concatenate the array item to the end of the `refused` paragraph's `textContent`, followed by a comma and a space. @@ -604,13 +733,15 @@ Specifically, we want you to: We've already provided you with: -- `let i = 0;` — Your initializer. - `refused.textContent +=` — the beginnings of a line that will concatenate something on to the end of `refused.textContent`. - `admitted.textContent +=` — the beginnings of a line that will concatenate something on to the end of `admitted.textContent`. -Extra bonus question — after completing the above tasks successfully, you will be left with two lists of names, separated by commas, but they will be untidy — there will be a comma at the end of each one. Can you work out how to write lines that slice the last comma off in each case, and add a full stop to the end? Have a look at the [Useful string methods](/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods) article for help. +Extra bonus question — after completing the above tasks successfully, you will be left with two lists of names, separated by commas, but they will be untidy — there will be a comma at the end of each one. +Can you work out how to write lines that slice the last comma off in each case, and add a full stop to the end? +Have a look at the [Useful string methods](/en-US/docs/Learn/JavaScript/First_steps/Useful_string_methods) article for help. -If you make a mistake, you can always reset the example with the "Reset" button. If you get really stuck, press "Show solution" to see a solution. +If you make a mistake, you can always reset the example with the "Reset" button. +If you get really stuck, press "Show solution" to see a solution. ```html hidden

Live output

@@ -629,7 +760,7 @@ const refused = document.querySelector('.refused'); admitted.textContent = 'Admit: '; refused.textContent = 'Refuse: ' -// let i = 0; +// loop starts here // refused.textContent += ; // admitted.textContent += ; @@ -694,7 +825,26 @@ solution.addEventListener('click', function() { updateCode(); }); -const jsSolution = 'const people = [\'Chris\', \'Anne\', \'Colin\', \'Terri\', \'Phil\', \'Lola\', \'Sam\', \'Kay\', \'Bruce\'];\n\nconst admitted = document.querySelector(\'.admitted\');\nconst refused = document.querySelector(\'.refused\');\n\nadmitted.textContent = \'Admit: \';\nrefused.textContent = \'Refuse: \'\nlet i = 0;\n\ndo {\n if(people[i] === \'Phil\' || people[i] === \'Lola\') {\n refused.textContent += people[i] + \', \';\n } else {\n admitted.textContent += people[i] + \', \';\n }\n i++;\n} while(i < people.length);\n\nrefused.textContent = refused.textContent.slice(0,refused.textContent.length-2) + \'.\';\nadmitted.textContent = admitted.textContent.slice(0,admitted.textContent.length-2) + \'.\';'; +const jsSolution = ` +const people = ['Chris', 'Anne', 'Colin', 'Terri', 'Phil', 'Lola', 'Sam', 'Kay', 'Bruce']; + +const admitted = document.querySelector('.admitted'); +const refused = document.querySelector('.refused'); + +admitted.textContent = 'Admit: '; +refused.textContent = 'Refuse: '; + +for (const person of people) { + if (person === 'Phil' || person === 'Lola') { + refused.textContent += \`\${person}, \`; + } else { + admitted.textContent += \`\${person}, \`; + } +} + +refused.textContent = refused.textContent.slice(0,refused.textContent.length-2) + '.'; +admitted.textContent = admitted.textContent.slice(0,admitted.textContent.length-2) + '.';`; + let solutionEntry = jsSolution; textarea.addEventListener('input', updateCode); @@ -747,33 +897,52 @@ textarea.onkeyup = function(){ ## Which loop type should you use? -For basic uses, `for`, `while`, and `do...while` loops are largely interchangeable. They can all be used to solve the same problems, and which one you use will largely depend on your personal preference — which one you find easiest to remember or most intuitive. Let's have a look at them again. +If you're iterating through an array or some other object that supports it, and don't need access to the index position of each item, then `for...of` is the best choice. It's easier to read and there's less to go wrong. -First `for`: +For other uses, `for`, `while`, and `do...while` loops are largely interchangeable. +They can all be used to solve the same problems, and which one you use will largely depend on your personal preference — which one you find easiest to remember or most intuitive. +We would recommend `for`, at least to begin with, as it is probably the easiest for remembering everything — the initializer, condition, and final-expression all have to go neatly into the parentheses, so it is easy to see where they are and check that you aren't missing them. - for (initializer; condition; final-expression) { - // code to run - } +Let's have a look at them all again. + +First `for...of`: + +``` +for (const item of array) { + // code to run +} +``` + + +`for`: + +``` +for (initializer; condition; final-expression) { + // code to run +} +``` `while`: - initializer - while (condition) { - // code to run +``` +initializer +while (condition) { + // code to run - final-expression - } + final-expression +} +``` and finally `do...while`: - initializer - do { - // code to run - - final-expression - } while (condition) +``` +initializer +do { + // code to run -We would recommend `for`, at least to begin with, as it is probably the easiest for remembering everything — the initializer, condition, and final-expression all have to go neatly into the parentheses, so it is easy to see where they are and check that you aren't missing them. + final-expression +} while (condition) +``` > **Note:** There are other loop types/features too, which are useful in advanced/specialized situations and beyond the scope of this article. If you want to go further with your loop learning, read our advanced [Loops and iteration guide](/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration). @@ -783,17 +952,18 @@ You've reached the end of this article, but can you remember the most important ## Conclusion -This article has revealed to you the basic concepts behind, and different options available when looping code in JavaScript. You should now be clear on why loops are a good mechanism for dealing with repetitive code and are raring to use them in your own examples! +This article has revealed to you the basic concepts behind, and different options available when looping code in JavaScript. +You should now be clear on why loops are a good mechanism for dealing with repetitive code and are raring to use them in your own examples! If there is anything you didn't understand, feel free to read through the article again, or [contact us](/en-US/docs/Learn#contact_us) to ask for help. ## See also - [Loops and iteration in detail](/en-US/docs/Web/JavaScript/Guide/Loops_and_iteration) +- [for...of reference](/en-US/docs/Web/JavaScript/Reference/Statements/for...of) - [for statement reference](/en-US/docs/Web/JavaScript/Reference/Statements/for) - [while](/en-US/docs/Web/JavaScript/Reference/Statements/while) and [do...while](/en-US/docs/Web/JavaScript/Reference/Statements/do...while) references - [break](/en-US/docs/Web/JavaScript/Reference/Statements/break) and [continue](/en-US/docs/Web/JavaScript/Reference/Statements/continue) references -- [What’s the Best Way to Write a JavaScript For Loop?](https://www.impressivewebs.com/javascript-for-loop/) — some advanced loop best practices {{PreviousMenuNext("Learn/JavaScript/Building_blocks/conditionals","Learn/JavaScript/Building_blocks/Functions", "Learn/JavaScript/Building_blocks")}} diff --git a/files/en-us/learn/javascript/building_blocks/looping_code/loop_js-02-farm.png b/files/en-us/learn/javascript/building_blocks/looping_code/loop_js-02-farm.png deleted file mode 100644 index 0b22b9349091fdcda8a5c26becbea6747e148ea0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41232 zcmbq(V{|7$({F72gN-+~ZQD*Zwry{cP5$A=wr$(m*tTsuH_!9l_rv{s=k%%RuCDr3 zO;uN)nK>P%C@+BshXV%!0)i+dDXI(t0uBTL0b_vy|K`|JQaF6yAk2m2gg`)Qqv78T zA-~6<&dL(PAXSriC*P7Ein6L=5)QH$F7+7B^$?Jdklq%@A_}` z`ThU!G3_d5_mBT8-|#*4zrqdwm9P8ZTtBmWh3?q+KYYypB9G5LW4V0e{09&o@Z+0e z{@2z2m~(DmP_h2@YJB5#YWw`VGre;)zIisfcJ$r81@tmUz7;38&S$nx1{QXFLt|<> zhep?q$JUP9#}<1R_B8)ic1%l{gj-}cFB zn%X>_+q;_BI!D2yEN<=#jZNM-y-P2t`+oe&&VO0GD{bS;9=?B?hGuQt{9#wh`x&51|-76G_Iyjq} z?4j-Nq@X#~=l$E+IJ;jyx=rlfNbTE1u&XT^*)=biY??cAsh9;duiQR=SUkLq=~x3X ztyn$2tDZXWsa=TcTCbZqM6$1iwyrLp*q=YRb+4RrESrI_tSTMbvo4ylEt&SKTMTbq z@vNRV$(tD8zA6~rSv$SU9N4liozcr4)5;hPX)+@IdPCh=}* zTQ~tWE~WQxMYXRQ=8WTeG_eMCS{6>pCk{!(4&b;o@`U$L`nCy0_Dyb`-M_rk2XqW= zT&SiF_pP2`x;CEOy}Z1AEF9c+EuR|Yj*o6#j;$ZRe|#O?JbP5lT|K_;UOe{CZ|`3{ z^-Qe{FYmRE%sc1xE$&~q7LUd>P9?Q304s)V)7!&pC-jp#YRA?sbBB%7dO>yat9vIi znnx9*T8ai%zM2JxzpEnBMOj`2WM>Ni28Rv`1%VLbRj-4N4atA_(l$v!%)RgrN0|-w zdPouh;n3=1$@$@w?$Q!j^H1^`BtAtJiE(J*Ynf1Ay<^w?&Vb6rZS@>>HHP?9hJUiZ zd2YloN$rRRD{Z(h^Y0608?kFGao^8!iUe->6#UPArjH_V3w4#x$Sm)E^~375;oZ^D zsSUkCYor|(Y!DDa5Ghe1Rgcy4^eF|Bkstm~0J4yMRH_l8@WYx|RNI73QRxD;hUE3z ze{A+8PMF~Htad3-!DXh$I~?FCe==F|9Tb``k|M+Ckn5Pz1PtXp7i_T%42FroXuP%t zFX^Akn^d#)JIfw_>7zgh0sep6&DYQs!S5${u$RNLtr-hKe1Co4C)~fscjevhsp1fh zTkj791)HW_AK;O&yS^_c_9N}qJ|g)6EegJmd{XY20(^OnLhB^@@y^+IXW7#|gqP9X z@lG5SlZw=&myV|Q+RB$u7Pi4H0-ui(%$HEU@+5&R9QYp$qzP$!Kq{TJ>`XKrYpTnR z2HHkyzub>(R_0LXq!`c8voQt)BL#f~BOV)7f}TDnGHTss#TBW1l%&g!BsH8L&ST?G zykEiIUs>W%H#Mkb4lK>JwXHZbmRoT^oOGG@-E9b@4R3cv2sxPQm;5qk5Jhi>tG4Ag zPz%=> zPgS@Ja$}BjQmC9*O4w+d^gXBWei_%}M~RDv^-^cY>uoBK-u?GNb#u$rtB%3O@##3? zl0dYh>#q48MSY3sVHtCOzO!F~pI%&2E6o@tgC%oXFxU@d1&klyT zrVdwtVCYAMLaZuLEKcQr*K^-Map@+qH z+p#b-B(SRO5bLWytg1(jS2Mk__%!uB$$=8XXYEZ$@BvFIgbU8;1gafMm1e`+vVp}H z|5eCMb{NwS%-y`1l}Ef?4#EprylfA|-%qGnCoq8i?Z~m+gSLRoh%d�}W^0r+##9 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 V>k5