import { addBanner, addArticle, addTitle, addHeader, addParagraph, addClassParagraph, addSubHeader, addOrderedList, addUnorderedList, addBlockquote, addInset, addInsetList, addInsetCodeListing, addInsetBulletList, addImageWithCaption, addButtonGroup, addSidebar, addSyntax, menu, global_menu } from '/scripts/import.js';
import { local_menu } from '/scripts/webdev.js';
const heading = document.querySelector(".heading");
const global = document.querySelector(".global_menu");
const local = document.querySelector(".local_menu");
const sidebar = document.querySelector(".sidebar");
const main = document.querySelector(".main_content");
heading.append(addTitle("Learning the JavaScript Language"));
heading.append(addParagraph("Joe Chellman - LinkedIn Learning - May 2023"));
heading.append(addParagraph("Iterating with Loops"));
main.append(addHeader("for loops: Sequential ")) ;
main.append(addParagraph("JavaScript provides the sorts of loops you will be familiar with if you have done any programming and the syntax is standard so rather than provide a standard example, I think it would be better and more instructive to use a real world example from my own website and also look at making some improvements to it."));
main.append(addParagraph("Bear in mind that my website may change as I learn more JavaScript and other technologies so here is a screenshot of one of the pages as it is right now."));
main.append(addImageWithCaption("./images/website.png", "A screenshot of a page from my website with menus."));
main.append(addParagraph("Notice the menus near the top of the page. There are a lot of different ways I can generate these. The top menu is the same on all of the pages on my site so I use a function that has a couple of arrays, One of these holds the text for each of the links and the other holds the URLs which become the href values for each link. The loop looks like this."));
main.append(addImageWithCaption("./images/menu1.png", "The global_menu() function."));
main.append(addParagraph("We'll take a look at this line by line except for the for loop and then see how the loop fits in with the rest of the code."));
main.append(addParagraph("To start with, we declare our function and notice that we don't supply any formal parameters so we will not pass any parameters when we call it. We then declare an array called new_menu and we give this the values that we want our links to display as text so this is what the user will see and what you see in the first menu in the screenshot from my website shown above."));
main.append(addParagraph("The second array is similarly initialised with the links which will provide the href values for each individual link. We then have a line of code that uses the createElement function to create an HTML div element called global and this will be the element that holds the menu links."));
main.append(addParagraph("Finally, we return global and we will see what that holds when we look at the for loop."));
main.append(addParagraph("The first line of the loop sets up the control variable called index which is initialised with a value of zero, the condition for allowing the loop to continue and the change that happens to the control value in each iteration. Note that starting with a 0 value and incrementing it by 1 in each iteration is not compulsory, you can start from another value and use a different method to update the control value such as decrement it by 1 for each iteration."));
main.append(addParagraph("In most cases, when you use a for loop or if you see one in somebody else's code, it will start with a value of 0 and increment that value by 1 for each iteration so it is important to remember that you can change both if you need to."));
main.append(addParagraph("The condition is where we determine when this loop will stop. We want it to execute once for each value in the arrays so we use the length of the array to do that. The array as it is has 9 elements so we could have specified the condition as"));
main.append(addSyntax("index < 9"));
main.append(addParagraph("but using the length means that we can add or remove elements from the array and the loop would still iterate the correct number of times."));
main.append(addParagraph("As the loop goes through the iterations, index will start with a value of 0. In the for loops code block, we start by creating an anchor element called link (again, using createElement). We then set the inner HTML of that link to the first element (with the index value 0) of the mer_menu array."));
main.append(addParagraph("The next line sets an attribute for the link using the setAtttribute method with the attribute's name given as the first argument to setAttribute and the value we want it to have, which is the corresponding element from new_menu_links, as the second argument."));
main.append(addParagraph("The next line is for troubleshooting so when the code is run, I can check that the link value is being setup correctly and then the final line of code adds that link to the global div. That global div now holds the Android link and you can see that is the first menu item in the screenshot above."));
main.append(addParagraph("The arrays both have elements numbered from 0 to 8 (nine in total) so when the index value gets to 9, if the loop ran again, it would try to access the 10th element and so the loop stops before that happens."));
main.append(addParagraph("Just a side note, you can also break out of a loop using the break command but you normally want it to run a fixed number of times so it is quite rare to see that."));
main.append(addParagraph("Similar to that is the continue statement which will break out of the current iteration but will then check the condition and if that indicates the loop should run again, it will continue on to the next iteration."));
main.append(addParagraph("After the loop finished, global, the div holding the links, will then return that to the function call so in any given web page, I can call it with"));
main.append(addSyntax("global.append(global_menu());"));
main.append(addParagraph("Note that in this context, global represents an element in the HTML page (so it is not the same thing as global in the loop). The function is called first and that returns the global div with our menu links and that whole element is attached to the page element and so it displays the menu."));
main.append(addParagraph("A couple of things to note about this, it wasn't necessary for me to hard-code the array values in to the function and I could have passed them over when making the function call. This has the advantage of greater flexibility for the function in that it will then be able to generate any menu simply by passing an appropriate set of value over to it."));
main.append(addParagraph("The trade-off there is that I then have to hard-code the arrays into every function call so this becomes a choice between making it more flexible or making it easier to call. In this case, it is going to be called a lot on my website but the values will never to change so it makes sense to hard code the values into the function and use it only to generate this specific menu. In the next loop, I have chosen to make the function easier to call because the menu is the same for every page so I don't need the flexibility."));
main.append(addParagraph("Next, we'll take a look at the local_menu() function and this is very similar to the global_menu() function. The main difference is that it is intended to be a bit more general purpose. If you look back to the screenshot from my website above, notice that like most of the pages on my site, this page displays two menus, the global menu which allows the user to switch between subjects and the local menu which allows the user to navigate between the pages of the course or set of pages currently being viewed."));
main.append(addImageWithCaption("./images/menu2.png", "The local_menu() function (original version)."));
main.append(addParagraph("In terms of the code, the main difference is that this function takes three arguments, the menu, the menu links and the base. These are the same as the arrays that are hardcoded into the global_menu() function but in this case, we are not hard-coding them, so the function will set up a menu with whatever arrays we pass over to it but we do still have the same type of values, an array with the text for the links and an array for the href values but in this case the href values are incomplete. The following image shows an example of a page that uses this function to generate its local menu."));
main.append(addParagraph("The arrays that are going to be passed over to the function can be hard coded into the function call. However, there are ten pages using this menu so that would mean hard coding the menu arrays 10 times and if it changes, the same changes would have to be made to each of the ten pages."));
main.append(addParagraph("I used this function for a while but it can be a nuisance to use and it is obviously better to avoid repeating code because that introduces more opportunities for errors, can be harder to test since an error might occur in any one of the ten links and anytime there is a change, each of the links would have to be tested again."));
main.append(addParagraph("Before we look at a way to resolve this, let’s take a closer look at one of the links. If I click the menu item labelled Understanding the Power of HTML, the href value for that link is"));
main.append(addSyntax("/webdevelopment/htmlessentialtraining/power.html"));
main.append(addParagraph("The link is made up of three parts as follows."));
main.append(addInsetBulletList(["webdevelopment – this is the general grouping for the course.", "htmlessentialtraining – this is a reference to the course (actually, it's the name of the folder that contains the course on the website)", "power.html – this is the actual page."]));
main.append(addParagraph("In order to simplify this, I have a function that only requires me to pass over the name of the course and the fully formed menu will be returned. The function looks like this.£"));
main.append(addImageWithCaption("./images/menu3.png", "The local_menu() function (current version)."));
main.append(addParagraph("The main difference between the current version of the local_menu() function and the original version is that it only takes one value and that is the name of the course."));
main.append(addParagraph("We then initialise the arrays, but we didn't have these passed into the function when it was called. Instead, we call a couple of functions that return the arrays. The course name that was passed over to local_menu() is passed to these functions (you can see the start of one of those helper functions in the above image) and all that happens there is that the required array is returned and we do that for both the menu array (remember, that holds the page names which will appear in the links such as 'Understanding The Power of HTML') and the menu array which has the href values (such as power.html)."));
main.append(addParagraph("The base value is the rest of the href value (ie, /webdewvelopment/htmlessentialtraining/) and the reason I have this is just to make it a little easier to code the arrays. This function is held in a JavaScript file called webdev.js and it only provides the menus for Web Development course in order to simplify this base value."));
main.append(addParagraph("The base value can be generated by taking /webdevelopment/ (which would be the first part of any of these links for any Web Development course) and adds the name of the course followed by the final /. For the HTML Essential Training course, the base value is therefore"));
main.append(addSyntax("/webdevelopment/htmlessentialtraining/"));
main.append(addParagraph("We then use the for loop to iterate over these arrays and create each link with this line of code"));
main.append(addSyntax("var link = document.createElement(\"a\");"));
main.append(addParagraph("The text for that link is added with the line"));
main.append(addSyntax("link.innerHTML = new_menu[index];"));
main.append(addParagraph("and the href value is set using"));
main.append(addSyntax("link.setAttribute(\"href\", new_base+new_menu_links[index]+\".html\");"));
main.append(addParagraph("Side note – this is not ideal in fact because the we don't really need a function to generate the base and we could in fact code this as"));
main.append(addSyntax("link.setAttribute(\"href\", \"/webdevelopment/\" + course + \"/\" +new_menu_links[index]+\".html\");"));
main.append(addParagraph("However, there are two reasons for using the function. The first is that I simply didn't think of using the actual directory name as the value to call the local_menu() function with so the first couple of times I used this, I had called it with a different value and so the base() function corrects that."));
main.append(addParagraph("For reference, the base() function now looks like this"));
main.append(addImageWithCaption("./images/menu4.png", "The base() function."));
main.append(addParagraph("This simply creates a called root and sets it to"));
main.append(addSyntax("/webdevelopment/"));
main.append(addParagraph("It then adds the course name and / to root and returns it. If every course used its directory name to call this function, only the line"));
main.append(addSyntax("return root+course+"/";"));
main.append(addParagraph("would be required and in fact, there would be no need to use any conditional statements to check the value that was passed in and convert it to the directory name. If I fix both of these courses so that they do call local_menu() function, I would then have the choice of either not using this function at all or using it with one line of code."));
main.append(addParagraph("The other advantage of using the function is that it makes it a lot easier to read the code in local_menu(). If you compare"));
main.append(addSyntax("link.setAttribute(\"href\", new_base+new_menu_links[index]+\".html\");"));
main.append(addParagraph("and"));
main.append(addSyntax("link.setAttribute(\"href\", \"/webdevelopment/\" + course + \"/\" +new_menu_links[index]+\".html\");"));
main.append(addParagraph("the first is a little clearer because the base() function is taking over setting the value for base so even if it isn't really required, it does help with readability."));
main.append(addHeader("for loops: Enumerative"));
main.append(addParagraph("Our in depth look at the for loops used to generate the menus on this site also serves to illustrate an important point. As you can see, the way in which the menus are being generated has changed over time and changes like this in a production environment can happen for a number of reasons."));
main.append(addParagraph("For example, JavaScript itself is continually evolving and changing and as new techniques and functionality appear, you may find that there is a better way to do things and that can lead to a change in your code."));
main.append(addParagraph("A really big advantage in the method I am currently using, particularly when generating the local menus is that the call is as simple as it could possibly be so if there are any changes in future (such as the changes to the base() function, the changes only have to be made in the function itself rather than the call to the function and that means that a change in one place can be applied to every page for every Web Development course without my having to change each of them."));
main.append(addParagraph("In this section, for example, we will look at a different way to write a for loop that deals with a collection such as an array."));
main.append(addParagraph("I should also add that I am still learning about JavaScript and a lot of the changes I make to the way my website is coded is driven by that learning process. For instance, after learning the material in this section, I may well change the way I code the for loops in my menu functions so I will use those functions as a way to demonstrate how they could be written using this type of for loop."));
main.append(addParagraph("With a for loop, we have some flexibility in that we can start the loop at some value other than 0 or 1 and we have some control over how the control variable changes during each iteration. The downslide (albeit not a big deal) is that when you are writing the code for the loop, you do have to specify these values. This also has the advantage that it is quite explicit so the code should be fairly clear."));
main.append(addParagraph("However, you will find that a lot of the time you are using the for loop in order to iterate over the values in each collection as we did with the arrays in our menus. In this type of situation, we want to set up one link for each pair of element in those arrays. We can do this with a fairly standard for loop like this"));
main.append(addSyntax("for (let index=0; index < new_menu.length; index++) {"));
main.append(addParagraph("Because it is so common to want to process each element of an array, there is a special loop to do that and that is the for…in loop and the syntax for that is something like"));
main.append(addSyntax("for (var index in new.menu) {"));
main.append(addParagraph("We can make this change and leave the code block the same and there is no difference to the way in which the menus are produced."));
main.append(addParagraph("However, there is a drawback with this syntax. For example, if this code runs with an array that has 10 elements, the value of index will essentially be 0 up to 9 corresponding to the index values of each array element but there is no guarantee that the order will be preserved. In practical terms, for a menu this may mean that the links don't appear in the expected order. If the last item in the array is a link labelled Conclusion, for example, it might not display as the last link in the menu so if the order is important, as it is here, the more conventional syntax of the for loop is recommended."));
main.append(addParagraph("If we are using a collection with key value pairs such as an object, we can use the for…in loop to iterate through the keys (our conventional sequential for loop won't work so well here because we don't have a standard numerical value in the keys that we can reference with index)."));
main.append(addParagraph("Using the for…in loop we can use each key in the map to access the corresponding value but it doesn't allow us to access the values directly – in other words, the for…in loop iterates over the keys, not the values. However, there is a variation on this loop that does iterate over the values and that is the for…of loop. The syntax is almost identical so"));
main.append(addSyntax("for (var index of new.menu) {"));
main.append(addParagraph("Quick side note. JavaScript, as you know, is an object oriented language and it uses a mode called Prototypical Inheritance (more on that later). Essentially, this means that when you are enumerating over an object, it might have no properties of it's own but it may have inherited properties. That is something we can check for in a loop so let's say we have a simple object like this."));
main.append(addSyntax("var pages = { first: \"Home\", second: \"About Us\", third: \"Contact Us\", fourth: \"JavaScriptPlayground\", fifth: \"Blog\"};"));
main.append(addParagraph("We could write a for…in loop like this."));
main.append(addInsetCodeListing(["for var p in pages] { var p: string", " if pages.hasOwnProperty(p)} {", " consoles.log(p, pages[p])", " }", ")"]));
main.append(addParagraph("I won't go into any detail on this but just something to be aware of when you are creating a loop to iterate over objects like this where the object might not have any value (property)."));
main.append(addHeader("Set and Map: Newer Loopable Data"));
main.append(addParagraph("Both sets and maps are relatively new to JavaScript and have been borrowed from other programming languages but also to some degree (in the case of sets) from mathematics. A set is similar to an array but doesn't allow duplicate values and a map is a collection of key value pairs so it is similar to an object in some ways!"));
main.append(addParagraph("Both sets and maps unsurprisingly are objects and can be created using the new keyword which will invoke its constructor like this."));
main.append(addSyntax("let mySet = new Set();"));
main.append(addParagraph("or"));
main.append(addSyntax("let myMap = new Map();"));
main.append(addParagraph("The set or map will be initialised with the data that you pass over to it in parentheses so in these examples, they are both empty when created. All JavaScript objects have a constructor and can therefore be created with it, even a relatively simple object like a number but it is not commonly used unless it has to be."));
main.append(addParagraph("In general, it is required when the object being created is a bit more complex and that applies both with sets and maps."));
main.append(addHeader("Set Methods"));
main.append(addParagraph("Unlike an array, elements in a set cannot be accessed directly using an index value or subscript, but it has its own access methods."));
main.append(addSyntax("mySet.add('juno') ;"));
main.append(addParagraph("adds the string 'juno' to the set."));
main.append(addSyntax("mySet.has('juno') === true;"));
main.append(addParagraph("will return true if the string 'juno' is part of the set."));
main.append(addParagraph("The MDN Web Docs has more information on Sets including a list of its methods and links to the instance methods such as the two shown here."));
main.append(addHeader("Map Methods"));
main.append(addParagraph("As mentioned earlier, maps are a lot like objects but they do preserve the order of the items stored (a map is an ordered collection). As with sets, maps have their own methods for adding and accessing its data."));
main.append(addSyntax("myMap.set('bar', 'foo');"));
main.append(addParagraph("adds a key value pair to the map where 'bar' is the key and 'foo' is the associated value."));
main.append(addSyntax("myMap.has('bar');"));
main.append(addParagraph("will return true if map contains a key value pair where the key is 'bar'."));
main.append(addParagraph("Again, you can get more information on Maps from the MDN Web Docs including a list of its methods and links to the documentation for its instance methods."));
main.append(addParagraph("This is just a very basic introduction to sets and maps which should give you some idea of what they are and how they work, but you will probably want to explore them further."));
main.append(addHeader("While Loops"));
main.append(addParagraph("JavaScript support both while and do…while loops and the syntax is identical to that found in programming languages such as C or Java. A while loop looks like this."));
main.append(addImageWithCaption("./images/while.png", "The syntax for a while loop."));
main.append(addParagraph("The key feature of a while loop is that it will continue iterating until some condition is no longer true. For example, in the loop shown above, the loop will continue until i has a value that is not less than 10."));
main.append(addParagraph("Notice that the control variable, in this case i, is not initialised as part of the loop so we have to set it to an appropriate value before we start the loop. We can't do that inside the loop because the value would be set to 0 on each iteration and would therefore never reach a value of 10 or greater and we would have an infinite loop where i is being set to 0 and then incremented to 1 for every iteration."));
main.append(addParagraph("One feature that is, to my knowledge, unique to a while loop is that it tests the condition before the first iteration and that means that the code inside it's code block is not guaranteed to run. For example, let's say that we set i to a value of 10 before running the loop."));
main.append(addImageWithCaption("./images/while1.png", "A while loop where the code block is not executed."));
main.append(addParagraph("When the condition is tested the first time, it returns a false value and so the code inside the loop is not executed at all. This means that the value of i doesn't change."));
main.append(addParagraph("Something else to look out for in a while loop is that you want to be sure that the control variable will eventually cause the condition to fail. In our example, this is a very basic while loop that doesn't really do anything useful other than demonstrate the syntax. We are just increasing the value of i for each iteration until it reaches 10 so this is really just an over-complicated way of setting the value of i to 10."));
main.append(addParagraph("The syntax for a do…wihle loop is very similar to that of a while loop as shown here."));
main.append(addImageWithCaption("./images/dowhile.png", "The syntax for a do…while loop."));
main.append(addParagraph("The difference is that the condition in a do…while loop is evaluated after the code in its code block has executed so the code will always be executed at least one, even if the control value is such that the condition always evaluates to false or at least evaluates to false the first time it is tested."));
main.append(addParagraph("In general, you would likely want to use a for loop in order to have some code run a set number of times such as when processing the elements in an array."));
main.append(addParagraph("You would typically use a while loop when you don't know how many iterations will be needed. For example, if you have a guessing game where the player has to input a number between one and a hundred until the correct number is guessed, you might use a while loop which runs as long as an incorrect number is input so the loop executes when the right answer is guessed. You would probably also include a condition inside the loop that checks for the correct number and outputs an appropriate message to confirm that."));
main.append(addParagraph("A do…while loop is used in similar circumstances but where you want to be sure that the code executes at least once. A typical usage here is with a menu where the user should select a number between 1 and 10, for example with q to quit. If you use a do…while loop where the condition is that the control variable doesn't equal 'q' or 'Q' and where the code within the loop presenter the user with the options and instructions on how to select an option or to quit, you can be certain that the user will see those instructions and will know how to either select an option (which would generally cause some other code to run and would take you back to the loop – and therefore to the menu – when it is done) and will know how to quit from the menu."));
addSidebar("webdev");