heading.append(addTitle("Learning the JavaScript Language"));
heading.append(addParagraph("Joe Chellman - LinkedIn Learning - May 2023"));
heading.append(addParagraph("Functions"));
main.append(addHeader("Basic Functions"));
main.append(addParagraph("We haven't covered functions yet but I did mention a couple of my own functions used to generate menus for my website. These are very basic functions but they illustrate a lot of the basic points about functions."));
main.append(addParagraph("In its very simplest form, the syntax of a function is like this"));
main.append(addParagraph("Note that function is a keyword used to let JavaScript know that this is a function. The name of the function is global_menu() and there is nothing in the parentheses so this function has an empty arguments list. This simply means that we can call the function without passing any arguments to it."));
main.append(addParagraph("The function name can be used to call the function so if we execute a line of code like this"));
main.append(addParagraph("This will execute the function and this just means that all of the code between the opening curly brace at the end of the first line and the closing curly brace at the end of the function will be executed."));
main.append(addParagraph("You might recall, this returns an array of links for the menu. The function call itself is only part of the line so let's look at each part in turn."));
main.append(addParagraph("In order to fully understand what is going on here, you need to know a little bit about the HTML. Most of the pages on this site use an almost identical HTML file that looks something like this."));
main.append(addImageWithCaption("./images/html.png","The HTML code I use for pages where the content is generated with JavaScript."));
main.append(addParagraph("The HTML is just 5 divs and there is also a CSS file that is used to position these divs on the page, in each case the class should provide at least a rough idea of the content that goes into each of them. The global div is the one that contains the global menu. The CSS uses a grid layout where each area of the page is named so I also use the name global for that to keep things consistent and to make the intention clearer."));
main.append(addParagraph("The only thing that varies between the HTML used for different pages is the title and the link to the JavaScript file that creates the page content and so each HTML page also has a corresponding JavaScript file. As a result, there is no content in the HTML file and so everything visible inside the viewport for each page is coming from the JavaScript."));
main.append(addParagraph("In that file, I have created a variable for each of the five divs including the following:"));
main.append(addSyntax("const global = document.querySelector(\".global_menu\");"));
main.append(addParagraph("This statement uses the querySelector method (note, methods are another type of function we have already seen to target the div with class global_menu. That means I can reference it within the file and can apply methods and functions to it. Essentially, it is now a variable in JavaScript. If we now go back to this line, it will probably make a little bit more sense now."));
main.append(addParagraph("So we are taking that variable, global, which references the div in the HTML and we apply the append method to it and what we are appending is the result we get from running the global_menu() function and the result is that the menu is applied to the global div in the HTML file and is displayed on the page."));
main.append(addParagraph("The local_menu() function is pretty similar as we had already seen and the major difference here is that we are passing an argument over and so the first line of the function is"));
main.append(addParagraph("It is important to remember that functions have both format and actual parameters. The formal parameters are the parameters we use when we code the function so that is"));
main.append(addSyntax("(course)"));
main.append(addParagraph("It's quite common and even normal to use the formal parameter in your function to do some processing but in this case we are just passing it on to the functions that generate the arrays and the base value for a menu and then using those to actually create the menu."));
main.append(addParagraph("When we call this from within our JavaScript code, the call will look something like this."));
main.append(addParagraph("Actually,, this is what makes the function so useful and allows us to reuse it. Throughout this site, you will find that there are multiple calls to this function with different values being passed over for different courses."));
main.append(addParagraph("The value we pass over such as"));
main.append(addParagraph("are the actual parameters or the actual parameter in this case since there is only one. Obviously, we want to be able to call the function with an appropriate parameter for the course we need a menu for but we don't want to have to write a function to generate the menu every time we need a new menu. We resolve this with formal parameters."));
main.append(addParagraph("When we write the function, we probably don't know what values are going to be passed over to it and in a sense, we don't want to know because we want it to be work for any value we pass over. So when we write the function, we are really saying that when the function runs, it will get a value which we don't yet know so we will give it a temporary name, in this case course and we will refer to it as course within the function code."));
main.append(addParagraph("So, we call the function and pass it the value"));
main.append(addParagraph("This tells the function that we want it to run and to use this value for course so when the local_menu() function calls the menu() function which also uses course as the name of the formal parameter, it will pass over \"learningthejavascriptlanguage\" as the actual parameter. In that sense, you can think of the formal parameter as being a variable name used in the function and the actual parameter as being the value of that variable whenever we call it."));
main.append(addParagraph("It's worth noting that in a strongly-typed language such as Java, when you write a function that takes one or more arguments, you do also have to specify the type of those arguments as well as the type of the value returned by the function so when we declare a function, it's going to look something like this."));
main.append(addParagraph("This makes it a little easier to work with the function because you can see from the declaration that it expects you to pass a string value to it and it returns an array of strings."));
main.append(addParagraph("This is assuming that you can view the code and you might also need to look at the code executed by the function in order to understand how to use it effectively. This is something that is true for all functions but sometimes you want a function to be usable by other people without giving them access to the code and if that's the case, you would likely want to create a specification for the function."));
main.append(addParagraph("This would include the signature which is the line"));
main.append(addParagraph("Essentially, the purpose of a signature is to define the input and output values for a function and you might also want to provide some more information about these values so the user knows what to input and what to expect as a return value."));
main.append(addParagraph("In addition, a bit of information about what the code actually does can be helpful. However, since JavaScript allows you to pass any value over to the function, it is probably more important to provide a full specification for a function if its purpose is not immediately obvious because that would allow you to tell the user how to use the function."));
main.append(addParagraph("For our local menu function, that might be something like:"));
main.append(addInsetBulletList(["Signature - function local_menu(course)","input – a string value which should correspond to the name of a course on this site.","output – an array of links used in the local menu (that is, the menu specific to a course)."]));
main.append(addParagraph("You might also want to add a bit of descriptive text explaining the purpose of the function, how it should be called and where it should be called from and what happens when it is called."));
main.append(addParagraph("For my own website, it's perhaps not critical to provide this but it is certainly good practice and I do sometimes find that when I revisit a function after not seeing the code for a while, I have to read over it to remind myself of how it works so I think it is a good idea to do it for your own code but even more important if it is code that will be used by someone else!"));
main.append(addParagraph("Another way in which you can create a function in JavaScript is with a function expression which essentially creates a variable and sets its value to an anonymous function like this."));
main.append(addParagraph("This is not really very different from the way we declared the global_menu() function and the only difference is that the mane of the function goes before the word function but overall, the effect is (as far as I know) the same and the way in which you call the function is also the same so you would run the function assigned to the speak with variable with a conventional function call."));
main.append(addSyntax("speak();"));
main.append(addParagraph("Arguments and Parameters in Functions"));
main.append(addParagraph("Let's look at another example of a function."));
main.append(addParagraph("This is an example of a function that takes one argument and expects this to be a string which it then converts to make it sound like something Elmer Fudd would say. There are a couple of lines of code that replace a lower case r with a w and an upper case R with a W."));
main.append(addParagraph("Notice that it has included a conditional statement which checks the type of value that has been passed to the function and gives an error if that is not a string value. In this case, the error message isn't very helpful but in a real world example, the error message would be more likely to include information about the error and would perhaps tell the user what should be input."));
main.append(addParagraph("Note that if you omit this check, the function would still work perfectly well. All it is doing is taking the input, replacing the letter r with the letter w without changing the case and then returning the value so if you passed it a value like this"));
main.append(addParagraph("you will just get the same string returned and if you provide a value that isn't a string, you will still get that value being returned. So the error checking isn't especially helpful here but it does nicely illustrate the point that if it is important that the function only gets the right type of argument, you can add some code to test for that and only run the rest of the function if the correct type has been passed over."));
main.append(addParagraph("It's also worth noting that the function as it is shown in the image above checks that the parameter has the right type but doesn't check to see if a string passed to it actually contains the letter r (or R) so it is not guaranteed to have any effect but you could write some code to check for that if it was important."));
main.append(addParagraph("If we look at the code that is executed when the parameter is not a string it is"));
main.append(addParagraph("At this point, you have probably seen console.log() so often that you may just not notice that we are using console.error() here which has more or less the same effect but with console.error, the formatting of the output may be different and it can also provide more traceability for the error. I didn't see any difference when trying that out from a terminal, but in a browser, running the function with console.error() and console.log() does show the difference as you can see below."));
main.append(addImageWithCaption("./images/fuddify1.png","The difference between console.error() and console.log()."));
main.append(addParagraph("The main difference is that the error is highlighted in red so if nothing else, it is at least highlighting the fact that we have an error!"));
main.append(addParagraph("Creating a function can have another advantage and that is it can help to make your code clearer. For example, let's say that you have this conditional in your code"));
main.append(addSyntax("if ( a % 2 === 0)"));
main.append(addParagraph("Essentially, we are testing to see if a returns a true or false response depending on whether the remainder of a divided by 2 is zero. Note, we re not checking the value directly, we are checking if it equlas zero so a zero result will give us true."));
main.append(addParagraph("You might notice that we will get a zero result for even numbers and 1 for odd numbers so if this evaluates to true, meaning that the remainder is 0, a is an even number. That may or may not be the intention of testing this particular condition but it's hard to think of another reason for testing if a number is divisible by 2 (ie, an even number)."));
main.append(addParagraph("Putting this into a function allows us to give that function a more descriptive name so we might create the function with the name IsEven() and pass over a number to it where the function will return true if that number is odd or false if it is even. We can then write the same code as"));
main.append(addSyntax("if ( isOdd(a)) "));
main.append(addParagraph("In this case, it is much easier to see what it is we are testing for."));
main.append(addHeader("More on Function Arguments"));
main.append(addParagraph("You can, as we have seen, write a function that takes multiple arguments and in general, you will probably want to provide the correct number of arguments in the correct order and just as importantly, with the correct types. In many cases, your code will still work if you don't do that but will probably not do what you expect. To give an example, let's say that I call my local_menu(), I hve to provide one string argument."));
main.append(addParagraph("When the function gets that argument, it will use it to get the arrays that it needs to complete it's task. If I pass it an argument that isn't a string or is a string, but doesn't match one of the conditions in the function generating an array, I will get an error because the function that generates the links will be trying "));
main.append(addParagraph("For this page, the function is called like this"));
main.append(addParagraph("When the argument is passed over to the function, it is then passed over to the menu() function to get the menu text and also to the menu_links() function to get the href values. You might remember, these functions are just a list of conditional statements which could actually be written as a switch statement and these simply test the condition and return the appropriate array when a condition matches (in other words, when it finds the value that was passed over to the function)."));
main.append(addParagraph("If nothing matches, the function will simply end and return control to the function that called it but it doesn't return anything. I have added a line at the very end of the function that outputs a message to the console to say that the function completed but didn't return anything."));
main.append(addParagraph("We do also use the same parameter with the base function which does return a default value which is just"));
main.append(addParagraph("I have also added a line just after this function is called that will log this returned value to the console."));
main.append(addParagraph("The output is now going to look like this and notice that I have the web developer tools open on the console tab to see what is happening."));
main.append(addImageWithCaption("./images/arguments1.png","The result when the local_menu() function is called with an invalid value."));
main.append(addParagraph("We can see that both the menu and menu_links functions completed and that's not really surprising. The parameter is being treated as though it were a string and so these functions are quite happy with it but they don't return anything. That means that both of the variables we set up to hold the returned arrays will have a null value."));
main.append(addParagraph("The base function actually worked as expected and returned a value for new_base which we can see logged in the console. Next, we create a div to hold the links and then move on to the for loop. The first line of the loop is"));
main.append(addSyntax("for (let index=0; index < new_menu.length; index++)"));
main.append(addParagraph("We want this loop to iterate once for each link we want to generate so I used the length of one of the arrays in order to determine the stopping condition for the loop, but since the array variables both have a null value, we are trying to apply the length method to an object that is not an array and this is where we get the error."));
main.append(addParagraph("If you look at what is being displayed in the web page, the title at the top is there as is the global_menu() but nothing else on the page is being displayed because the error in the for loop has stopped execution of the JavaScript file at that point and since this is generating all the page content, the rest of the page is also being blocked."));
main.append(addParagraph("Notice that the error message is quite descriptive here and it tells us that the error happened because new_menu is undefined so it doesn't have a length property and so we get an error when we try to access it."));
main.append(addParagraph("I think that this raises a couple of interesting questions. The fact that JavaScript isn't doing any type checking can be really convenient because it means that functions will often just work whatever value was pass over to it and we saw that with the base() function."));
main.append(addParagraph("Nevertheless, you may find some of your code is not doing what it is supposed to if it is passed a value that you don't expect. "));
main.append(addParagraph("Another important point to consider is what the consequences of an error occurring. If a function is using one or more parameters provided by the user such as when filling out a form for instance, you can't guarantee that the user will provide the expected data so having the function work regardless of what is passed to it may be a good thing, depending on what you will do with that data."));
main.append(addParagraph("If it is critical to get the right data you can add some code to check the inputs and ask the user to try again if they provide the wrong or invalid data. This is a runtime error and you can try to predict when the user might input data and add code to validate the user inputs and you absolutely should do that when the data is critical."));
main.append(addParagraph("The error we saw is slightly different in that it is what you might think of as a development error. It's something that can be fixed when you test your website and obviously, the fact that you see an almost completely blank screen when you load the page is a good indication that there is an error somewhere."));
main.append(addParagraph("Some errors in JavaScript will either prevent the page from loading at all or will happily allow you to load your content until the error is encountered and then will prevent any further content from loading. That's the type of error we saw and the approach to troubleshooting it is very different. I could write code to validate the parameter after it has been passed to the function but that's not really going to help because the parameter is part of the JavaScript code rather than user input so if you are loading the page and it fails, it's a little bit harder to fix than asking the user to input the correct data!"));
main.append(addParagraph("This is something we want to fix before the code goes live or as soon as possible after. For me, I would just reload a page when it has been changed and then fix any errors that I find. This is more of a bugfix and in this case, the bug would be fixed by ensuring that the local_menu() function is passed a valid value."));
main.append(addParagraph("At this point, we are probably starting a little away from the main point of this section which is functions but I think it's a worthwhile diversion and it does in some ways relate to functions. So let's look at some of the tools and techniques that can help you to find and fix errors."));
main.append(addParagraph("When it comes to avoiding errors, functions themselves are hugely beneficial because you have some code such as my local_menu() function which will be called from almost every page on this site and that is a lot of pages! Putting this code in a function means that every page that calls it is using the same code nut they don't care what that code is or how it works. The only important thing from the perspective of a single page is that it can pass a value to the local_menu() function that ultimately causes the local menu to appear."));
main.append(addParagraph("That's not quite the whole story, but most of the complexity of generating the menu is there and I use other functions to actually generate the arrays for local_menu() but they just take the parameter and pass over the arrays that match that parameter to local_menu()."));
main.append(addParagraph("This gives us two benefits. The first is that if there is an error, although it will be more serious since it will affect most of the site's pages, it is also much easier to fix since I only need to fix one function."));
main.append(addParagraph("The second is that if I wanted to, I could change the way the function is implemented and it would still work the same way without making changes on each individual page provided I didn't change the number or type of the parameters. For example, I can change the function that generates the arrays so that it uses a switch statement without making any other changes."));
main.append(addSubHeader("Troubleshooting: The Browser"));
main.append(addParagraph("There are several ways in which the browser can help you troubleshoot an issue with a web page which we saw earlier but I will mention them again briefly here. I have different ways to generate the JavaScript calls that make up the files that generate for, as an example, this page and quite often I will do that outside of my development environment."));
main.append(addParagraph("For instance, for this course, I am writing the content as a word document and then using a combination of auto-correct such as typing £p and a space which converts to"));
main.append(addParagraph("or find and replace. To do this, I add my own tags to the text so £p for example could be added to the start of every paragraph and then I can do a global replace with all of the instances replaced by the call to addParagraph."));
main.append(addParagraph("I then copy this into the JavaScript file, save it and then view the page in my browser. Sometimes it works first time although I can't actually remember a time when it did! So the first thing that tells me there is an error is if I see a blank screen or if only part of the page is displayed. We saw that earlier where I showed the effects of sending invalid data to the local_menu() function so that can be really useful in telling you where the error occurred."));
main.append(addParagraph("In addition, the console in the browser developer tools is incredibly helpful here so when I see an issue in the page, I normally go straight to the console which will give you some idea of what the error is and where it was found. We can see this below."));
main.append(addSyntax("article.append(addImageWithCaption(\"./images/browser.png\", \"Troubleshooting my JavaScript code in the web developer tools console.\""));
main.append(addParagraph("So that tells me that the problem is with this line"));
main.append(addSyntax("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(addParagraph("The error tells me that there is an unescaped line break which essentially means that I have opened a string with the first double quote but not closed it so the browser thinks that the line break at the end of the line must be part of the string I want to display. I can fix that by closing the string and the call."));
main.append(addSyntax("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(addParagraph("This is a kind of a rinse and repeat type of process so I will save the changes, sync them to the web server and reload the page. When I do that, it the page now looks like this."));
main.append(addImageWithCaption("./images/browser1.png","Still troubleshooting my JavaScript code in the web developer tools console."));
main.append(addParagraph("That's a function called with the wrong name so I would generally search for that incorrect call in my code in case there are more than one instance of it and will either use find and replace to fix them all or just edit the line if there is only one."));
main.append(addParagraph("If I go through the same process again and refresh the page, it looks like this."));
main.append(addImageWithCaption("./images/browser2.png","Still troubleshooting my JavaScript code in the web developer tools console."));
main.append(addParagraph("Notice that in the console, we do still have some messages which I log for troubleshooting purposes and haven't gotten around to disabling yet but more importantly, there are no errors."));
main.append(addParagraph("You can also see that the sidebar is now populated and one of the nice things about that is that the call to get that sidebar content is always at the end of every page. This wasn't by design, but it is a really helpful troubleshooting aid because I can see that if it does display content, it means that the browser got to the end of the JavaScript file without any errors so this tells me that everything is okay even without the console."));
main.append(addHeader("Troubleshooting: The IDE"));
main.append(addParagraph("This also helps with the prevention of errors by autocompleting code as I type, particularly those function calls so if I am coding JavaScript directly in my IDE, whether that is VS Code or Dreamweaver or even if I am using Notepad++ (all of which I do use), this is a huge help. This helps to avoid errors and also the syntax highlighting can make it easy to see if I have mistyped something."));
main.append(addParagraph("It can also be helpful if I have coped some code over from an editor that doesn't offer that such as Word because I can quickly scan through the text and see if there is anything that looks wrong."));
main.append(addParagraph("A fairly common scenario there is where I have copied some code over that includes text with quote marks inside a function call that itself encloses the string parameter in double quotes. You can see that below."));
main.append(addImageWithCaption("./images/dreamweaver.png","Syntax highlighting in Dreamweaver"));
main.append(addParagraph("As you can see here, the unescaped quotes are causing Dreamweaver to interpret parts of the string as code and it is easy to see so I can just go and escape the quote marks until it looks right. You can see in line 77 of that Dreamweaver code, there is an example of what this should look like. There are also some other ways in which an IDE can help you to avoid errors but I don't want to get too sidetracked with that which could be a course entirely on its own."));
main.append(addParagraph("Another benefit you get from using a good IDE is code completion which provides a number of suggestions you can select from and this will usually include your own functions. For example, in a JavaScript file, I want to add an addParagraph() function call I can just type para and then select addParagraph from the list of suggestions as shown below."));
main.append(addImageWithCaption("./images/dreamweaver1.png","Code completion in Dreamweaver"));
main.append(addParagraph("This is useful for a number of reason including speed (it is easier to type), accuracy (its less likely that you will introduce spelling errors in to your code) and it can be helpful if you can't remember the precise name of a function. You can type a sequence of letters that you know does appear in the function name and then select it from the list of suggestions."));
main.append(addParagraph("It can also be a good learning aid because it might throw up some function names you weren't aware of such as HTMLParagraphElement."));
main.append(addParagraph("JavaScript itself has a few features that can help to avoid errors although here, we are mainly getting back to the side of run time errors where coding in a particular way can help you avoid or deal with user errors."));
main.append(addParagraph("Again, that's not really the point of what we are looking at here but there are a couple of things that relate to how we write functions so they are worth covering here."));
main.append(addParagraph("The first is default values for parameters. If you have a scenario where a user may not provide all of the data the function needs, you can provide defaults, As an example, lets say we have a function like this."));
main.append(addParagraph("We expect that the user will provide a string with their name and a number with their year of birth and we can use that to calculate their age. If the user doesn't provide a value for year, the code might not work as expected so we can help to avoid problems with the code by setting a default value like this."));
main.append(addParagraph("Now, if the user inputs their age, the function will tell them that they are 124 years old assuming the current year is 2024. This is probably not a good example, but it does allow us to write the function in a way that guarantees we will have some value for a particular parameter if the user doesn't provide it."));
main.append(addParagraph("Notice that in this example, I chose a default value which would make the user older than the oldest person currently alive so it is easy to see that the returned value is not realistic. For example, if I used 2000 as the default value, it might tell the user that they are 24 when they are actually 25 and that just gives the impression that the code is performing the calculation incorrectly!"));
main.append(addParagraph("Another useful features of JavaScript functions is that you can actually pass it as many parameters as you like, regardless of how many are declared. This is kind of similar to passing an array of arguments over to a C function. JavaScript seems to accept any parameters you pass over to a function as being an array and you can treat them as such."));
main.append(addParagraph("For example, you might have a function that will take an arbitrary number of integer arguments and returns their sum. We can set up the function without any arguments. The function is "));
main.append(addParagraph("In the function, we begin by setting the initial value of total to zero. We then use a for loop and this uses the length of the arguments array (which holds the arguments you pass to the function) so it is set to the number of arguments passed to the function."));
main.append(addParagraph("Since it is an array we can use the normal array syntax to access the individual argument which we see in the line"));
main.append(addSyntax("var number = arguments[i];"));
main.append(addParagraph("In the first iteration, for example, i has a value of 0 so number would be set to the value of the element with an index value of 0, in other words, the first number in the list passed to the function. The rest of the function is pretty standard so you have a conditional to check if the argument actually is a number and if it is, it is added to the total. Finally, the function returns the total."));
main.append(addParagraph("The main things to take from this is that the arguments are passed to a function as an array and regardless of how the function is written, we can access any of those arguments as an element of the arguments array so arguments[0] for instance, will always give you access to the first argument."));
main.append(addHeader("Objects, References and Functions"));
main.append(addParagraph("In JavaScript, when you pass an object to a function, it is important to remember that you are not passing a copy of the object, but a reference. That reference is to a memory location where the object is stored and the reason this is important is because it means that in effect, you are dealing with a global entity."));
main.append(addParagraph("To give some idea of the significance of this, consider the fact that we very often declare variables such as integer values inside a function and these will normally only have scope inside the function. An example of this is where we use I as a control variable in a for loop. Since it doesn't (or shouldn't) have scope outside of the function, once the function completes, the value we have assigned to I is discarded."));
main.append(addParagraph("For this reason, we can use that same variable name in loops in other functions and we don't have to worry about whether any changes we make to it will have an impact on how it is used in other functions. If we declared it as a global variable, this might give us unexpected results if we set its value to something in one function and then use it in another function where we expect it to have a specific value when the function is called, but it has a different value."));
main.append(addParagraph("A loop control variable is possibly a bad example of this because you will probably initialise it (usually to 0) before you start the loop but the basic principle is that any function or any code that uses the variable i is going to use the same copy so you may find its value changing unexpectedly."));
main.append(addParagraph("Similarly with an object, when you pass it to a function, since you are passing it by reference, any changes you make to the object's state may have implications for other parts of your code."));
main.append(addParagraph("Incidentally, if you are wondering why this is the default behaviour, the reason is simply that unlike an integer or even a string value, an object can be very large so you don't really want to have multiple copies of it if that can be avoided and passing its reference to a function is one way to do that."));
main.append(addParagraph("This raises a couple of interesting points and one is that it is possible, and in some cases the norm, to pass a copy of some variable rather than a reference to it and if that's the case, modifying the value in the function does not change it outside of the function. This is called passing by value."));
main.append(addParagraph("It is also worth remembering that when we do pass a value to a function, particularly if it is a value provided by the user, it is usually good practice to check the value that is being passed to the function. This is important in terms of the actual value being passed in and also in terms of the data type because if you get a value with either an unexpected value or type, your code may not work the way you expect it to and it may even break your code!"));
main.append(addParagraph("Another interesting point is that when you create a function where the intention is to modify an object and if you want to modify the original object, you don't need the function to return it. On the other hand, if you want to keep the original intact, you can create a copy if it within the function and make any changes to that. You can also return the copy of the value if you want to have both the original and the modified copy of the object to be available after the function has completed."));
main.append(addParagraph("The following image shows two different versions of a function that will illustrate some of these points. The functions are transmogrify(calvin) and transmogrifyCopy(calvin). In both cases, the function takes an object called calvin and so both are getting a reference to that object. In the transmogrify(calvin) function on the left, the function modifies that object so when it finishes, that object will have the value we set for form within the function."));
main.append(addImageWithCaption("./images/reference2.png","The transmogrify(calvin) and transmogrifyCopy(calvin) functions."));
main.append(addParagraph("For example, if the random number function returns a 2, form will be set to 'grey wolf' and when we check the value after running the function we find that it now has the value of 'grey wolf' for that form property."));
main.append(addParagraph("The function didn't return anything because its purpose is simply to change that value and since it is modifying the value of the calvin object inside the function, it doesn't need to return it."));
main.append(addParagraph("If you compare this to the function on the right, notice that this introduces a new variable called newForm and sets randomNumber to a number between 1 and 5. It then sets the value of newform to one of the options based on that number so again, if the value is 2, newForm will be set to ;grey wolf' but notice that we are not setting any value in the object so that original calvin object stays the same (its form property still has the value 'human boy'."));
main.append(addParagraph("It does have a return statements and the return value is an object with the same properties as the original calvin object as shown here"));
main.append(addParagraph("The new object has the same properties as the calvin object and we are setting the value for name and bestFriend by getting these from calvin and we are setting the value for newForm to the value generated by the function. So this is object is identical to the calvin object except for the form property which can be different. Note that this object is a different entity to the original object but the thing that makes it a different entity is that it is stored in a different area of memory and would be referenced by something other than calvin. This would be the case even if all of the properties had the same values as the properties in calvin."));
main.append(addParagraph("For example, we might want to call it calvinCopy and you might have noticed that we create this object in the transmogrifyCopy(calvin) function but there is no reference to it. In other words, we didn't give the object a name. An object without a reference is pretty much useless because without that, you won't have any way to access it."));
main.append(addParagraph("We could have taken care of that inside the function by creating an object called calvinCopy and returning that but the problem there is that the function would only ever return an object called calvinCopy. The way we would do the same thing with this function would be to create a variable called calvinCopy and assign the result of running the function to it. So"));
main.append(addParagraph("will create a variable called calvinCopy and then run the function which creates a copy of the calvin object, modifies it and then returns it and now calvinCopy references that new object. That means that we can create as many copies of the object as we want and assign it to a new variable each time so it is a more flexible way to write the function."));
main.append(addParagraph("One final point I want to make here which might actually be obvious is that an array is an object as we have mentioned previously. I think that is worth reiterating here because when you pass an array to an object, you are again passing over a reference to that object so if the array is modified inside the function, those changes will still be applied to the array when the function completes."));
main.append(addHeader("Functions are Objects"));
main.append(addParagraph("We have already seen that we can pass an object to a function and in JavaScript, functions are object which means that you can pass a function into another function as a parameter. Let's look at an example of that."));
main.append(addImageWithCaption("./images/function.png","Passing a function in to another function."));
main.append(addParagraph("On lines 1 to 5, we have a function declaration and we have already seen a number of examples of functions written in this way. What we are doing here is creating a function which takes one argument called what which has a default value of 'Speaking!' which it outputs to the console 10 times."));
main.append(addParagraph("You might recall that the function itself doesn't do anything. What I mean by that is that if you declare this function in your code somewhere and then run the code, you will see that it hasn't actually displayed anything in the console. To do that, you must call the function from elsewhere in the code and when you do, whatever you pass to it (or the default value if you don't pass in anything) will then be logged 10 times in the console."));
main.append(addParagraph("So here, we have a function and it's called speakSomething() and we can invoke it with something like"));
main.append(addParagraph("From line 7 up to 11, we have something that looks very similar and we can see that it contains the same code (the same loop and output statement) as we saw in the function declaration, so is this also a function declaration?"));
main.append(addParagraph("In fact it is, but consider this line of code"));
main.append(addParagraph("which is different from the first line of the function declaration and you might think that the biggest difference its name is in a different place and that is actually not correct. The name of the function comes after the keyword function and that applies here as well but in this case, the function doesn't have a name (it is an anonymous function)."));
main.append(addParagraph("However, we have created a variable which is called speakSomething and we have initialised it with our anonymous function. Where we previously had (with our function declaration) a function called speakSomething(), we now have a variable called speakSomething which we can pass in to a function."));
main.append(addParagraph("For an example of this, the setTimeout function takes two arguments. The first of these is a function and the second is a numberic value which is time in milliseconds. It runs the function that was passed to it after the time passed as the second parameter has passed. For example, if we run this code (assuming the speakSomething variable has been set up to point to the function)"));
main.append(addParagraph("When we run it, the browser will wait for 5 seconds and will then execute the function which will output the default value 10 times. Quick sidenote in case, like me, you wondered whether we could pass an argument to the function when we run it this way and mote that I mean to the anonymous function that is referenced by speakSomething. If we run this code"));
main.append(addParagraph("which looks like we want the browser to wait 5 seconds and then output \"Well, hello!\" 10 times. Actually, it doesn't work. It does give you the output you expected but it ignores the second parameter so there is no delay in producing the output and in fact, if you ran that code like this"));
main.append(addParagraph("the result would be exactly the same."));
main.append(addParagraph("There are a couple of other interesting points worth making about functions written in this way. Firstly, consider this statement:"));
main.append(addSyntax("a = 5 * x;"));
main.append(addParagraph("This is a very simple expression where we multiply the value of x by 5 and assign the result to a. We were doing something similar when we assigned the function to the variable speakSomething. For that reason, this is sometimes known as a function expression."));
main.append(addParagraph("There are also a couple of Objects that you perhaps don't really need to know about but may find interesting. One of these is a global Object called Global and the method setTimeout is a method we get from Global. Since the object is global, we can call its methods from anywhere and this is why we can call it without specifying an object to send the 'message' to."));
main.append(addParagraph("Another one is Function which may be useful to know about because all functions are not only objects, but they are also descendants of Function."));
main.append(addParagraph("You may have seen when experimenting with JavaScript that you can type in a variable name at a command line, press return and the browser or command line will respond with the value of that variable. If the value of the variable is a function, this will return the name of the function with its data type, which function (if you don't include the parentheses)."));
main.append(addParagraph("If you do include the parentheses, the console or terminal will recognise the fact that you are executing the function. This means that you can execute it in the same way as you would if it were created with a function declaration. For example, you can do that with a statement such as"));
main.append(addHeader("Jargon: Scope in JavaScript"));
main.append(addParagraph("You probably know by now that you can create and initialise a variable in JavaScript with one of the following statements."));
main.append(addInsetBulletList(["a = 5;","var a = 5;","let a = 5;","const a = 5;"]));
main.append(addParagraph("These all do the same thing and have the same effect which is to allow us to reference a variable called a that currently has a value of 5. So that raises the question, what's the difference between them?"));
main.append(addParagraph("The answer is scope. The point of using let and var is to restrict the scope of a variable, but they do that differently, so let's look at each statement in turn and how this affects the variable. In other words, aside from creating the variable a with a value of 5, what does it do."));
main.append(addSyntax("a=5;"));
main.append(addParagraph("This isn't really doing anything else directly. Aside from creating the variable, it doesn't place any restrictions on how it is used. As a result, a is created as a global variable meaning that you can access it from anywhere. This is something we saw with the Global object and it's setTimeout() method. "));
main.append(addParagraph("As far as I'm aware, it is not possible to declare a variable in such a way as to make it available outside of the file in which it is declared so global, if that's the case, means available or accessible anywhere within this file."));
main.append(addParagraph("Note that I tried to declare a variable in this way as a test but that didn't work because the current version of Firefox I am using doesn't run the JavaScript if I try to declare a variable in that way."));
main.append(addSyntax("var a = 5;"));
main.append(addParagraph("This is also sort of declaring a variable as global but it defines global in a slightly different way. Let's say that you have some code like that shown below and we want to concentrate for now on the variables declared with var."));
main.append(addImageWithCaption("./images/scope.png","Where you declare a variable with var will affect its scope!"));
main.append(addParagraph("On line 6, the variable, myNum is declared and it is global to this file. We also declare it again in both the randomizer() and the doubelIt() functions and these are global as well. If all versions of myNum had the same scope, this would give you an error and the reason it doesn't is because global, in these case means global within he function you declare it in."));
main.append(addParagraph("If it isn't declared inside the function, it is global to the whole file and that is the case on line 6. When the browser executes a function that tries to access a variable, it will first check if the variable has been declared inside the function and if not, it will look for a variable that is defined outside of the function so if you remove the variable declaration on line 12, the code will still work but it will no longer use the variable that is local to the function (yes, this kind of arrangement does mean that a variable declared with var is local to that function or you can say that it is global but only within the function)."));
main.append(addParagraph("Note that it will not look inside another function (unless you have a function within a function in which case it would look inside the outer function)."));
main.append(addParagraph("For this reason, with var we can declare myNum on line 6 and then again on lines 12 and 25 and they are separate variables. When you log myNum to the console, the actual value logged will be dependent on where you are logging it from – in other words, where in the code you put your log statement."));
main.append(addParagraph("If you have a statement like"));
main.append(addParagraph("inside a function, it will use the value of myNum for the variable declared inside the same function although you can use the global keyword to make JavaScript look outside the function."));
main.append(addParagraph("We can see this In the randomizer() function, where we are logging the value of myNum that is local to the function on line 14 and also looking the global value on line 15."));
main.append(addSyntax("let a = 5; or const a = 5;"));
main.append(addParagraph("I'll cover these together since they have the same scope, the only difference being that one is a variable so you can change its value whereas the other is a constant and you can't."));
main.append(addParagraph("In terms of scope, we generally consider variables declare with let to be genuinely local variable and the reason is that where a var variable is local to a function or global within its function, a let variable is only accessible within the code block in which it is declared."));
main.append(addParagraph("For instance, in the examples provided for var, there is an if statement where we declare oneIsOne as a constant soi its scope is within the if statement's code block and we can log in to the console within the block. If we try to log it from elsewhere in the code, we get a reference error because that variable or to be more accurate, that constant doesn't exist outside of the if statement."));
main.append(addParagraph("If we try that again using let instead of const, the result is the same because the scope is the same for both const and let."));
main.append(addParagraph("However, if we try it with var instead of const, we can then log the value of oneIsOne outside of the if statement because it is now a global variable."));
main.append(addParagraph("Incidentally, if you try this yourself using let or const and then manually type out the console log statement or just the variable name, you will see that it doesn't appear in the list of suggestions so you will have to type it out in full and that is a useful indication that the variable name you are typing doesn't exist. "));
main.append(addParagraph("If you find yourself typing out the name of a variable and it doesn't seem to exist but you know that you did declare it elsewhere, this should tell you that there is no variable with that name that has scope so as far as the console is concerned, it really doesn't exist!"));
main.append(addHeader("Writing Shorter functions with Arrows"));
main.append(addParagraph("With arrow functions, we can write functions more concisely. The image below shows a number of different ways we cab write functions."));
main.append(addImageWithCaption("/images/arrow_functions.png","Several different ways to write a function and make it shorter with arrow functions."));
main.append(addParagraph("On lines 1 to 7 we have a function expression where we create a constant value called speak so the expression itself is pretty similar to most of the function declarations we have seen so far. The major difference is that the name we will use to reference the function has been removed from the function declaration so essentially the function doesn't have a name in the declaration (it's technically an anonymous function) but we then go and give it a name by setting the value of the constant speak to that function."));
main.append(addParagraph("I think it may be helpful to explain here, if it isn't already clear, that a function is just a way in which we can take some code that we want to be able to execute more than once. We use the name of the function or the variable we assign the function to reference it and basically that just means when we want to run the code, we call it using its reference."));
main.append(addParagraph("This is essentially functional programming where everything is a function and we can write JavaScript in that way. We probably shouldn't get too hung up with this type of definition, for our purposes it is enough to know that we can use a function to run a little piece (or maybe a big piece of code) with just a single function call."));
main.append(addParagraph("To give a concrete example, I want to be able to generate an HTML element where the content is displayed as a piece of text in hiragana. I already have functions that can generate a paragraph or div element and I can pass a string to one of these functions (depending on how I want to style it) and the string is hard-coded into the call and is generated by copying and pasting hiragana characters or by inserting the English for the phrase/word that I want In to Google translate and taking the output (which is usually a mixture of kanji and hiragana) and converting it to hiragana only using a website."));
main.append(addParagraph("That sounds like an awkward and time-consuming way to do things and it is. To get around this, I use a function that simply allows me to input a string using romaji and the function will convert it to hiragana for me and that is a much easier thing. Before I go ahead and describe the function and how it works, it might be helpful to explain what these things are for non-Japanese speakers."));
main.append(addInsetBulletList(["Romaji – Japanese written in the western alphabet.","Katakana – a Japanese syllabary where every character represents a syllable.","Hiragana – a Japanese syllabary where every character represents a syllable.","Kanji are Chinese ideograms and are used in Japanese, each character represents an idea and has its own sound."]));
main.append(addParagraph("Let's take a look at the function that handles this conversion."));
main.append(addImageWithCaption("./images/romajiToHiragana.png","The finction that converts romaji to hiragana. "));
main.append(addParagraph("Notice that the function returns a string so I can use it wherever a string is required. For example, the function call"));
main.append(addParagraph("is used to generate an HTML div containing the string value \"かいます\". The romaji equivalent is \"ka i ma su\" so I could use the romajiToHiragana() function to achieve the same thing without having to provide the hiragana like this."));
main.append(addParagraph("Both these statements result in exactly the same hiragana string being displayed in the page. Note that the romajiToHiragana() function only returns the string, so this doesn't have any effect on how the string is styled which is determined by the outer function, in this case addInset()."));
main.append(addParagraph("The problem with this function is that it generates a whole HTML element and there are times when I want to embed some hiragana in a line of English text so I have another function called insertHiragana() which is shown below."));
main.append(addParagraph("This is called using 3 string arguments in the order I want them to appear in the output so that's two straightforward strings that will appear in the output exactly as given and one string, the second argument, that is a romaji string. The insertHiragana() function calls the romajiToHiragana() function and passes it that argument, getting a string in hiragana returned and then concatenates all three strings to give the final string which will be displayed in the HTML element."));
main.append(addParagraph(" The point I'm making here is that I have a useful function which is not particularly complex but it is convenient for me to call it either directly or via another function and this shows how it can be called in different ways and I think that it also shows how useful functions can be."));
main.append(addParagraph("You will notice that both of these functions were created in the most conventional way for writing functions and I could rewrite the functions as arrow functions but ultimately, this wouldn't change how they were called so for example"));
main.append(addParagraph("would still be the way in which the function was called. This is intended to be a little bit of reassurance as well because it would be easy to fall into the trap of thinking that function expressions or arrow functions are quite mysterious and complicated and they do some weird things you can't do with a conventional function declaration."));
main.append(addParagraph("They're not and they don't. They are just a different way of writing a function. Whether any method is better or worse than any other, I haven't used arrow functions in my own code so I'm not sure. In general, arrow functions are a little bit more concise but within the function's code block, there is no difference so the benefit is marginal. However, if you are writing code with a whole lot of functions, that marginal benefit might become more significant."));
main.append(addParagraph("Even if you never write your functions in that way (or any of the ways described in this section) it is still important to learn about them because you will almost certainly see them in other people's codes so it is important to be able to read that code and understand what it is doing."));
main.append(addParagraph("The following demonstrates how we can shorten our code a little bit with arrow functions. Recall that the first line of the function expression was"));
main.append(addSyntax("const speak = function () {"));
main.append(addParagraph("This, of course, is not an arrow function but if we write it so that it is, this line becomes"));
main.append(addSyntax("const speak = () => {"));
main.append(addParagraph("Notice, however, that everything inside the curly braces if the same for both versions of the function so we are not changing anything at all about what happens when the function is called and there is no change to the way in which it is called. The only difference is how we write that first line."));
main.append(addParagraph("This might give you slightly smaller files sizes for your code but even if you are using a lot of functions, it's probably not going to make a huge difference so I would suggest that the best approach for you to take is to simply use the syntax you are most familiar or comfortable with but be aware of both so that you will understand other people's code better."));
main.append(addParagraph("When your function consists of a single line of code, the difference can be greater but the syntax can also be very different so it is important to be aware of how this can be expressed as an arrow function because when you see this in someone else's code, it won't be quite so obvious."));
main.append(addParagraph("For example, let's say that we have a line of code that returns a true value if a given number is even and a false value if it is odd. We can wrap this up in a function declaration like this."));
main.append(addInsetCodeListing(["function isEven(num) {"," return num % 2 ==== 0; ","};"]));
main.append(addParagraph("If we rewrite this as an arrow function, we get this"));
main.append(addParagraph("In this case, the arrow function is actually slightly longer so there is no saving in either typing or storage space but I think that it is clear that in both cases, functionally these are identical and you might typically call a function like this from within an if statement so that will be something like"));
main.append(addSyntax("if (isEven(x))"));
main.append(addParagraph("That call would be the same regardless of how the function is written."));
main.append(addParagraph("Since there is only one line of code in the function, we can shorten it further like this"));
main.append(addSyntax("isEven = (num) => num % 2 === 0;"));
main.append(addParagraph("In this version, we have removed the curly braces which we don't really need because there is only one statement within the function and we have dropped the keyword function which is implicit."));
main.append(addParagraph("Again, you can seen that the functionality is the same and we could use even the original function declaration and put this all on a single line of code which would look like this"));
main.append(addSyntax("function isEven(num) { return num % 2 === 0; }"));
main.append(addParagraph("which makes it easier to see the differences between these two versions and I think it is fairly obvious both that the functionality is the same and that we are just dropping parts of the syntax that the browser can infer in order to provide a more concise syntax."));
main.append(addParagraph("We can also reduce this a little more by removing the parentheses around the argument list which is possible here due to the fact that there is only one argument. If there were multiple arguments, this would not be possible and that gives us"));
main.append(addSyntax("isEven = num => num % 2 === 0;"));
main.append(addParagraph("As before, the best advice is to use whichever version of the syntax you are most comfortable with but be aware of the syntax used within arrow functions, particularly for the one-liners so that you will understand what is happening when you see it."));
main.append(addHeader("Three Little Dots Collect the Rest"));
main.append(addParagraph("Previously, we saw that it was possible to pass an arbitrary number of arguments to a function and then access these as an array although this is not actually a JavaScript array so it has some limitations. However, there is an alternative syntax that allows us to be a little bit more explicit. To see how this works, we will rewrite the function we had used to add an arbitrary number of integers together using this syntax."));
main.append(addParagraph("As a reminder, the original version of that function was"));
main.append(addImageWithCaption("./images/add_numbers1.png","The original version of the add numbers function."));
main.append(addParagraph("Inside the function, arguments passed over to it are referenced by the array name arguments. So the arguments become the element of the array and we use the arguments array to access them as shown in the line"));
main.append(addSyntax("var number = arguments[i];"));
main.append(addParagraph("One thing that may be obvious although we didn't really touch on this earlier is that this really only works because we are not passing any arguments to the function other than the arguments we want to be accessed from the array although, of course, it would be possible to achieve the same effect by simply including the additional arguments in the array although you would then have to be careful not to read that value in the loop."));
main.append(addParagraph("As an example, let's say that we want to pass some other argument such as an operator so we can perform any arithmetic operation on the array of numbers. The easiest way would be to pass that as the first element with index 0, you can then read that value as a string and perform different operations depending on the value and the loop would start counting from 0 rather than one."));
main.append(addParagraph("Now, let's take a look at the same function with the newer syntax."));
main.append(addImageWithCaption("./images/add_numbers2.png","The new version of the add numbers function."));
main.append(addParagraph("As you can see, the function itself is still the same except that we have an explicit reference to the array containing the numbers a user passes in to it and we use that reference in the function body. However, there's not really much of a difference between the two and neither really offers much of an advantage over the other so the syntax you would use is as much down to personal preference as anything."));
main.append(addParagraph("A concept I haven't mentioned yet is that of positional arguments which is, I think, fairly obvious in most cases. Consider this line of code"));
main.append(addParagraph("This is the local_menu() function we looked at earlier and it has three arguments as follows:"));
main.append(addInsetBulletList(["menu – this is an array containing the labels for the links.","menu_links – another array, this contains the name of the HTML page to link to.","base_link – when added to the entry in menu_links, this gives us the absolute address for the page."]));
main.append(addParagraph("When the function is called, the order in which these arguments are placed in the call is important. For example, the menu array might look something like this"));
main.append(addSyntax("\[\"Getting started\", \"Variables and scope\", \"Iterating with loops\"\]"));
main.append(addParagraph("and the menu links page would then look something like this"));
main.append(addParagraph("If I called the function and got these two arrays the wrong way round so I am passing in the array with the menu links as the first argument, the array with the menu descriptions as the second argument and the third argument in the correct place, the first link would look like this (as you would probably expect)."));
main.append(addParagraph("As you may know, a URL cannot contain spaces so that link is going to show the name of the HTML file (minus the html extenslon) and the link will be not valid – assuming it shows the link at all rather than throwing up an error!"));
main.append(addParagraph("The key point to take from this is that the function is performing some actions on the first argument, some on the second and some with the third so because of that, the order or positions the arguments take in the function call is very important. For this reason, we call these positional arguments."));
main.append(addParagraph("If we relate this back to the add numbers functions, the order of the arguments did not matter since all of the arguments were simply part of a list of numbers to be added together and that was true of both versions."));
main.append(addParagraph("However, passing this array of numbers as an explicit argument as we did with this version of the function"));
main.append(addImageWithCaption("./images/add_numbers2.png","Reminder of the new version of the add numbers function."));
main.append(addParagraph("means that we can add additional arguments without having to include them as part of the array. That means we can pass in an argument like an operator so the function will look something like this"));
main.append(addImageWithCaption("./images/add_numbers3.png","The add numbers function rewritten with positional arguments ."));
main.append(addParagraph("This syntax allows us to be a little bit more flexible with our arguments and is a good method of creating a function with multiple arguments where one or more of those arguments is an arbitrarily long list of values."));
main.append(addParagraph("One final point to make in case it is not obvious. Recall that within a function, the arguments array holds all of the arguments that are actually passed into the function and this is also true when you use the three dots notation to pass in an arbitrary number of elements."));
main.append(addHeader("Callback Functions and Looping"));
main.append(addParagraph("Callback functions are used a lot in modern JavaScript and we have already seen some examples of this. In essence a callback function is one that is passed into another function so it can be executed when needed and you will often see them, for example, in event handlers."));
main.append(addParagraph("To demonstrate this, let's say that we have a function called double it which takes a number as an argument and returns a number that is twice the original value. The function might look like this."));
main.append(addParagraph("Remember that an array in JavaScript is an object and one of its methods is called map(). This takes a function as an argument and performs it on the elements of an array, returning a new array with the modified values. For example, we could call this method on myNumbers and a new array to hold the doubled values like this."));
main.append(addParagraph("This will have the effect of running the double it function on each element of myNumbers and generating a new array which we are calling myDoubles and this array will be"));
main.append(addSyntax("[2, 4, 6, 8, 10];"));
main.append(addParagraph("Note that the doubleIt function in this example takes just one argument and that is the element from the array the map function is operating on and it is represented by number inside the function. That is true of any callback function used in this way so you don't need to worry about what data you are passing to them but it does also mean that the processing you can do inside the function might be limited."));
main.append(addParagraph("You will see the map function quite often if you spent time inspecting other peoples JavaScript code because it is very useful and therefore very common. For instance, you can often see it used to render a list of items in a user interface."));
main.append(addParagraph("That is one example of how a callback function can be used but you can also use it with a forEach loop as in this example."));
main.append(addParagraph("In this example, the function is passed as a whole function, it isn't defined separatelybut we have just passed over a complete function along with its definition. We could also simplify this a little by passing it over over as an anonymous function like this."));
main.append(addParagraph("This is perhaps slightly more concise but also a little more difficult to read. In either case, we are passing the function to forEach which is operating on an array called myNumbers and just logging each of those values to the console."));
main.append(addParagraph("I think it is worth noting here as well that this is very simple example and you probably wouldn't want to be doing anything complex in the function if you are going to pass it over like this. You can also write this in the same way that we wrote the doubleIt function where we just pass the function name over and define it elsewhere."));
main.append(addParagraph("Of course, since the doubleIt function is also very simple, we could have passed the whole definition over and we could also have passed it as an anonymous function which would look like this."));
main.append(addInsetCodeListing(["var myDoubles.map((number) +> {"," return number *= 2);","});"]));
main.append(addParagraph("As you might expect, event handlers commonly use callback functions in which case the, callback function is called in response to the event that it is monitoring. Consider this example."));
main.append(addParagraph("So not a particularly complex example of an event handler, but this is a bit more complex than the previous examples of callback functions we have seen."));
main.append(addParagraph("The first thing that happens here is that we are getting an element from the HTML page, the element with id myTextField. Next, we are using the addEventListener function to attach an event handler to that element and notice that we pass two arguments to it."));
main.append(addParagraph("The first is the event that it should listed for which in this case is the keyup event so essentially the handler will be triggered by someone typing something in myTextField. The second argument is the callback function which is an anonymous function in this example and it just logs a message to the console to indicate that someone has typed something in that field."));
main.append(addParagraph("For more information on callback functions can be found in the MDN Web Docs under <a href='https://developer.mozilla.org/en-US/docs/Glossary/Callback_function'>Callback function</a> and you can also get more information on the the <a href=' https://developer.mozilla.org/en-US/docs/Web/API/Element/keyup_event'>keyup event</a>."));
main.append(addParagraph("For more information on JavaScript functions, a good follow up to this course might be the LinkedIn Learning courses <a href='https://www.linkedin.com/learning/javascript-functions-17058591'>JavaScript: Functions</a> by Ray Villalobos or <a href='https://www.linkedin.com/learning/javascript-essential-training'>JavaScript Essential Training</a> by Morten-Rand Hendriksen. Ray's course was published in 2022 and Morten's was published in 2017 originally with a new version published in 2021 but was updated earlier this year."));