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("Operators and Control Structures")); main.append(addHeader("Simple Comparisons")); main.append(addParagraph("Let's say that we have two variables declared and initialised as follows:")); main.append(addSyntax("var one = 1, two = 2;")); main.append(addParagraph("If we want to compare two values, the most common way to do that is with the strict equality operator which is 3 equals signs so")); main.append(addSyntax("one === one")); main.append(addParagraph("will return true because obviously one is the same variable as one! We can switch this to test if the values are not the same using the string inequality operator by replacing the first equals sign with an exclamation mark so")); main.append(addSyntax("one !== one")); main.append(addParagraph("will return false. On the other hand")); main.append(addSyntax("one !== two")); main.append(addParagraph("will return true since these two values are not identical and for the same reason")); main.append(addSyntax("one === two")); main.append(addParagraph("will return false.")); main.append(addParagraph("This kind of strict equality or strict inequality is actually telling us a little bit more than just that the two variables or values have the same value, it will also check the type as well. To understand why that is significant, it is important to remember that JavaScript will generally try to guess what you mean when you type a value in somewhere and will convert values that don't fit. To illustrate this, let's take a look at the equality and inequality operators.")); main.append(addParagraph("The equality operator uses two equals signs and if we do something like this")); main.append(addSyntax("one == one")); main.append(addParagraph("we will still get a true value returned because the value is the same. However, we will also get a true value returned if we do this")); main.append(addSyntax("one == '1'")); main.append(addParagraph("Here, we are comparing a numerical value to a string, but if the string is converted to a number, the values are then the same and that's what JavaScript does. It will assume that you want to make a comparison of numerical values and will convert the string value to a number in order to do that. If you did this")); main.append(addSyntax("one == '2'")); main.append(addParagraph("JavaScript will do the same but the values would still be different and so you will get a false value returned. Similarly")); main.append(addSyntax("one != '2'")); main.append(addParagraph("will return a true value although it is worth mentioning here that although this demonstrates the usage for the inequality operator, this will always give you a true value because the values are not the same, so it really doesn't matter whether type is checked.")); main.append(addParagraph("There may be occasions when you will need to use the equality and inequality operators and that might apply for instance where you want to compare two values but you don't know (or care) what type those values have. However, since you know the circumstances under which the strict equality and strict inequality operators will return a true (or a false) value, they are more predictable and you are less likely to find values being equal when you didn't expect them to be.")); main.append(addParagraph("The relational operators are pretty standard in JavaScript so for example")); main.append(addSyntax("one < two")); main.append(addParagraph("will return a true value. ")); main.append(addSyntax("one <= two ")); main.append(addParagraph("will also return a true value as will")); main.append(addSyntax("two >= one")); main.append(addParagraph("If we flip these")); main.append(addSyntax("one > two")); main.append(addParagraph("or")); main.append(addSyntax("one >= two")); main.append(addParagraph("will return a false value.")); main.append(addParagraph("As you can see, these operations are reversible so if ")); main.append(addSyntax("one < two")); main.append(addParagraph("returns a true value (which it will in this example), you can change the order of the operands and reverse the operator")); main.append(addSyntax("two > one")); main.append(addParagraph("and that will also return a true value.")); main.append(addHeader("Arithmetic Operators")); main.append(addParagraph("The arithmetic operators are also fairly standard, particularly if you have coded in C/C++ or Java so you have + for addition, - for subtraction, * for multiplication and / for division.")); main.append(addParagraph("Where JavaScript is a little different is that / does not represent integer division so even if you perform an operation like")); main.append(addSyntax("36 / 5")); main.append(addParagraph("You won't get an integer response. You will in fact get ")); main.append(addSyntax("7.2")); main.append(addParagraph("As far as I can tell, there is no operator in JavaScript for integer division, but you can achieve the same effect with the Math.trunc() method so")); main.append(addSyntax("Math.trunc(36/5)")); main.append(addParagraph("Will get rid of the fractional part of the result giving you")); main.append(addSyntax("7")); main.append(addParagraph("However, JavaScript does have a modulus operator, %, so")); main.append(addSyntax("36 % 5")); main.append(addParagraph("will return 1.")); main.append(addParagraph("A good example of this would be where you were trying to determine whether a number is odd or even so let's say you have an integer variable, n, if you perform the operation")); main.append(addSyntax("n % 2")); main.append(addParagraph("this will return 0 if the number is even and 1 if it is odd. You may know that this type of operation is sometimes called clock arithmetic because you are essentially counting out (in this example) the number of time that you can subtract the second number from the first and giving you what is left over when you can no longer subtract it.")); main.append(addParagraph("You could actually quite easily write a function to do that and in that function, you would probably have a while loop so to perform an operation such as")); main.append(addSyntax("36 % 5")); main.append(addParagraph("You would probably do it something like this")); main.append(addInsetCodeListing(["let a = 36", "let b = 5", "while a > b {", " a = a – b;", "}", "print a;"])); main.append(addParagraph("The value of a will be reduced by 5 each time the loop executes and it will continue to do that while the condition evaluates to true. When we get to the point where a = 6, the loop will execute again and subtract 5 from 6 leaving 1.")); main.append(addParagraph("It will then test the condition which will now return a false value and it will print out the value of a which is now 1 and that is our remainder. Remember that division is really just repeated subtraction (just as multiplication is repeated addition).")); main.append(addParagraph("You can also insert a counter in that loop, set it to 0 before the loop starts and increment it once every time you successfully subtract 5 from 36 so you would need to add a statement within the loop that increments the counter if a is greater than b.")); main.append(addParagraph("It is worth pointing out that if you consider a statement like this")); main.append(addSyntax("20 % 2 === 0")); main.append(addParagraph("This is using the strict comparison operator and will return true if the remainder is zero so it returns true if 20 is an even number. You might wonder why anyone would use a computer to work that out since you can tell, just by looking at a number whether it is odd or even based on the last digit and 20, of course, is an even number.")); main.append(addParagraph("However, you would use this type of calculation if you don't know in advance the value of the number you will be testing so you could think of this as ")); main.append(addSyntax("n % 2 === 0")); main.append(addParagraph("where n is some unspecified integer. In other words, in a realistic programming scenario, we would use a variable for the first number. Not the 2 because if we change that, it will no longer be useful for determining whether a number is even or not!")); main.append(addParagraph("Just a quick side note, if you replaced 2 with any other number, it might still correctly identify an even number but will not work correctly 100% of the time. For instance, if we had")); main.append(addSyntax("n % 4 === 0")); main.append(addParagraph("That will return true for any number that is exactly divisible by 4 (that is, the remainder will be 0) and this actually works for 50% of even numbers but will also give an inaccurate result for the other 50% which illustrates the point that you can test your code as much as possible and may always get the right answer, but the code might still have a bug that is hard to detect because it does give you the right results a lot of the time.")); main.append(addParagraph("Now, let's look at another operation.")); main.append(addSyntax("counter = counter + 1;")); main.append(addParagraph(" Here, the expression on the right is evaluated first and the result is assigned to the variable counter. It doesn't matter that we are using the value of counter to calculate a new value for counter. This is basically saying, take the value that counter has, add 1 to it and then set counter to that new value. In short, it increments the value of counter by 1!")); main.append(addParagraph("Like other programming languages, JavaScript has a shortcut for that in the form of an increment operator")); main.append(addSyntax("counter++;")); main.append(addParagraph("You cam also write this in a slightly different format")); main.append(addSyntax("counter += 1;")); main.append(addParagraph("There is no advantage in using this syntax if you are adding 1 to counter but it has the advantage that you can use it as a shorthand to add any number to counter so")); main.append(addSyntax("counter += 10;")); main.append(addParagraph("will add 10 to the value of counter and")); main.append(addSyntax("counter += n;")); main.append(addParagraph("will add n to the value of counter.")); main.append(addParagraph("You can also use a similar syntax for minus so ")); main.append(addSyntax("counter—")); main.append(addParagraph("and so on.")); main.append(addParagraph("There is a similar syntax for multiplication that looks like this")); main.append(addSyntax("counter**2;")); main.append(addParagraph("You might expect that this will set the value of counter to 2 times the previous value so for example, if counter = 2, this operation will return 4. In fact it does, but it only doubles the value when counter does equal 2. If it has a value of 1")); main.append(addSyntax("counter**2;")); main.append(addParagraph("will return 1 and if it has a value of 3")); main.append(addSyntax("counter**2;")); main.append(addParagraph("will return 9 and that might give you a clue as to what it is doing. It is actually multiplying counter by itself so it is the same as ")); main.append(addSyntax("`counter * counter;")); main.append(addParagraph("whereas")); main.append(addSyntax("counter**3;")); main.append(addParagraph("is equivalent to")); main.append(addSyntax("counter * counter * counter;")); main.append(addParagraph("That probably tells you what it is doing which is counter to the power given so this is actually the exponent operator so in more general terms")); main.append(addSyntax("counter ** n;")); main.append(addParagraph("will return counter to the power n. However, this is an operator that will return 2 times the value of the operator and that is")); main.append(addSyntax("counter *= 2;")); main.append(addParagraph("and we can also replace 2 with any number or any variable that contains a number so")); main.append(addSyntax("counter *= 5;")); main.append(addParagraph("will return the value of counter multiplied by 5 and")); main.append(addSyntax("counter *= x;")); main.append(addParagraph("will return the value of counter multiplied by x.")); main.append(addParagraph("The plus operator will also works on strings, you might say that it performs a string addition and it is known as the concatenation operator so")); main.append(addSyntax("'cat' + 'dog';")); main.append(addParagraph("will return ")); main.append(addSyntax("catdog")); main.append(addParagraph("Notice that it doesn't put any spaces between the words so if you want to add one, you can either specify it as a string on its own or inset a space into one of the strings, so")); main.append(addSyntax("'cat ' + 'dog';")); main.append(addParagraph("or")); main.append(addSyntax("'cat' + ' dog';")); main.append(addParagraph("or")); main.append(addSyntax("'cat' + ' ' + 'dog';")); main.append(addParagraph("will all return the same thing and that is ")); main.append(addSyntax("cat dog")); main.append(addParagraph("As you can imagine, you can string together a whole load of additions to create a longer expression so")); main.append(addSyntax("1 + 2 + 4 + 8;")); main.append(addParagraph("for example, will return 15 and you can do that with string concatenation too so")); main.append(addSyntax("'cat' + ' and ' + 'dog';")); main.append(addParagraph("will return")); main.append(addSyntax("cat and dog")); main.append(addParagraph("Just a reminder, JavaScript will sometimes convert a string to a number or vice versa in order to make sense of your code but not always and it can sometimes be a little hard to predict. If you have")); main.append(addSyntax("'1' + '2';")); main.append(addParagraph("this will return")); main.append(addSyntax("'12'")); main.append(addParagraph("so there are a couple of important points there. Firstly, the value returned is not 3 which you might have expected but is '12'. Secondly, this returned value is a string, not a number and it seems that JavaScript performs concatenation rather than addition if both arguments are strings.")); main.append(addParagraph("It also seems to do the same thing if one of its operands is a string and the other is a number.")); main.append(addParagraph("One final point to mention is that if you do something like this")); main.append(addSyntax("counter * 3;")); main.append(addParagraph("this may look like something that will obviously give you an error and it will. However, you should remember that multiplication is simply repeated addition and so you might expect that multiplication with a string is just repeated concatenation.")); main.append(addParagraph("That is true in some programming languages, but not JavaScript so you would be wrong to think that but it's not totally unreasonable and you may have encountered other programming languages where it would concatenate as many copies of the string as the multiplier (3 in this case) but it doesn't.")); main.append(addHeader("Logical Operators")); main.append(addParagraph("In JavaScript, the logical operators are")); main.append(addSyntax("&& AND")); main.append(addSyntax("|| OR")); main.append(addParagraph("I wasn't sure if JavaScript uses short circuiting for AND so I ran a simple test that goes like this. Start by creating 2 variables which can have any names but I used c and d and gave them both an initial value of 0. I then executed this statement")); main.append(addSyntax("if (( c++ === 0) && (d++ === 0)) console.log(\"Both are zero\");")); main.append(addParagraph("JavaScript responds by outputting both are zero. You can then check the value of both c and d and you will see that they are indeed, not 0 any more!")); main.append(addParagraph("This may seem a little weird but we added an increment operator after both c and d which is why they both now equal 1. The reason we got the output we did is that the operator comes after the operand (technically, it is the post-increment operator).")); main.append(addParagraph("When the code is executed, it checks c and finds the value is 0 so that part of the condition is true and then it increments it. The same thing happens with d so since both parts of the condition evaluate to true, we see \"Both are zero\" in the output.")); main.append(addParagraph("Now, if we run that statement again without making any changes to c or d, we will no longer see that output because c and d both start out with a value of 1 so the condition is not true.")); main.append(addParagraph("The interesting part here is that we can check the value of c and we will find that it is now 2 because the first condition (c++ === 0) was evaluated and the increment operator then increases the value of c and if we run this repeatedly, we will see it continue to increase. However, the value of d remains 1, it doesn't change.")); main.append(addParagraph("If we start again, resetting c and d to 0 and changing the code to ")); main.append(addSyntax("if (( c++ === 0) || (d++ === 0)) console.log(\"Either c or d is zero, possibly both.\");")); main.append(addParagraph("We will run that four times and then check the values of c and d to see if they are the same. In fact, they are not. The value of c is 4 which you would expect but the value of d is now three.")); main.append(addParagraph("Since c started with a value of 0 and was incremented 4 times, we would expect its value to be 4 but it seems that c has been incremented 3 times.")); main.append(addParagraph("The reason for this is actually quite simple. In the first example, we were checking if both values were true so if we get a false value from the first condition (in other words, if c does not equal 0), the entire condition is going to be false regardless of whether d equals zero or not, so the second condition is not evaluated and consequently, d is not incremented. ")); main.append(addParagraph("In the second example, we only need one of these conditions to be true and when we run it for the first time, c does have a value of 0 so this statement is going return a true value regardless of the value of d so we don't need to check it and d is not incremented.")); main.append(addParagraph("When we run it a second time with c having a value of 1, we still get an overall true response and so we see the output")); main.append(addSyntax("Either c or d is zero, possibly both.")); main.append(addParagraph("because since we didn't bother to check d in the first iteration, it wasn't incremented and so it still has a value of zero and we get a true value returned.")); main.append(addParagraph("When we run it a third time, the interpreter will check the value of c, find that it is 2 (because it was incremented in both the previous iterations and we will still get false when we check if the value is zero so we check the value of d which is now one and we know longer get either c or d returning true so the overall result is false.")); main.append(addParagraph("We can run this as often as we like and we will increment both c and d in every iteration but having been incremented one more time than d, the value of c wi8ll always be one that than the value of d.")); main.append(addParagraph("You can contrast this with the first example where the entire conditional statement will only be true if both c and d are zero, checking the value of d isn't skipped in the first iteration and so both c and d taken on the value of 1. ")); main.append(addParagraph("For any subsequent iteration, we would only check the second condition if the first were true and so the value of d is never checked after the first iteration.")); main.append(addParagraph("We can sum this up by saying that the conditions are only checked if there is a possibility that it may affect the overall results. For example")); main.append(addSyntax("conditionA && conditionB")); main.append(addParagraph("is only true if both conditions or true so the second condition is only checked if the first condition is true. If it isn't, the statement can only return a true value and we don't need to check the second condition. ")); main.append(addParagraph("For")); main.append(addSyntax("conditionA || conditionB")); main.append(addParagraph("if conditionA returns true, since we don't need both values to be true, that is enough for us to know that a true value will be returned overall so we don't check the second condition and if it returns false, we will always check the second condition.")); main.append(addParagraph("This is known as short circuiting. Bear in mind the fact that we can link as many conditions as we like in a logical chain, eg")); main.append(addSyntax("If (a and b and c and d and e)")); main.append(addParagraph("Each condition is checked until a false value is returned and no other conditions are checked. Overall, a true value will only be returned if every condition is true.")); main.append(addParagraph("We could also do this with OR operators instead of AND, and a similar thing would happen. Each condition would be checked until one of them returns true and the interpreter would stop checking as soon as it finds one and will return a true response. So this time, we get a true response if any condition returns true and a false response if, and only if, all the conditions return false.")); main.append(addParagraph("A couple of points to add, the examples we have seen have been quite simple but they can be much more complicated but before I get into that, there is another logical operator we haven't seen yet and that is the negation operator (or NOT) which flips a Boolean value. The symbol for this is an exclamation mark. ")); main.append(addParagraph("Another point to make is what constitutes a true value and in most programming languages, this is a non-zero value so if a numberical variable has a value of 5, let's say, we can do this.")); main.append(addSyntax("if (a) {do_something()}")); main.append(addParagraph("So this will execute the do_something() function if a is true and it is because it's value is not zero. In some programming languages, a negative value is considered false but that's not the case in JavaScript so -3, for instance, would be considered true.")); main.append(addParagraph("When you put conditions together like")); main.append(addSyntax("`if (a && b)")); main.append(addParagraph("there is always a possibility that you end up with a statement that will always give the same value, that is, always true or always false. Consider this example")); main.append(addSyntax("if (a && !a)")); main.append(addParagraph("This will return a true value only if a is true and a is false and since that is not possible, it will always give you a false value. In a logical sense, a can only return a true value or a false value so in this example")); main.append(addSyntax("if (a || !a)")); main.append(addParagraph("this will always evaluate to true because we are checking whether the condition is true or false and it has to be one or the other!")); main.append(addParagraph("These examples are fairly obvious and you would be unlikely to make a mistake like that with such a simple condition, but when you have more complex logic, it is always possible that you will construct a statement or a condition that will either always evaluate to either true or will always evaluate to false.")); main.append(addParagraph("You can use truth tables to determine whether or not that will be the case. For more information see the Introduction to Truth Tables on the LibreTexts Mathematics site or Truth Tables, Tautologies, and Logical Equivalences on the Millersville University site.")); main.append(addParagraph("You might also find the Truth Table Generator on the Stanford website to be quite useful.")); main.append(addParagraph("One thing you may or may not have noticed is that the logical operators we have seen so far are binary operators. The && operator will usually look something like this")); main.append(addSyntax("a && b")); main.append(addParagraph("So, it takes two operands and it would not make any sense if one were omitted. For example")); main.append(addSyntax("&& b")); main.append(addParagraph("is most likely going to give you an error because you are missing an operand. Another operator we haven't looked at yet is the NOT or negation operator and this is a unary operator represented by an exclamation mark so a statement like")); main.append(addSyntax("! b")); main.append(addParagraph("is perfectly valid and the result is determined by the Boolean value of b. If b is true, ! b is false and if b is false, ! b is true.")); main.append(addSyntax("a ! b")); main.append(addParagraph("will give you an error because the expression has two operands where the unary operator expects only one.")); main.append(addHeader("Conditionals: if")); main.append(addParagraph("The if statement in JavaScript is pretty much the standard version found in other languages such as Java or C/C++. An example of this is shown below.")); main.append(addImageWithCaption("./images/if.png", "The syntax of an if statement in JavaScript.")); main.append(addParagraph("It's worth noting that you can experiment with this code in the console in the browser developer tools but it won't work in a terminal because the first line is a browser method that will open up an input box with the text in the command acting as the prompt. Depending on what you type into the box, you will see different messages being logged to the console.")); main.append(addParagraph("We then have a sequence of commands that will take some action depending on what you typed and it is the job of the if statement to compare this against a preset value to determine whether or not it's code should be executed.")); main.append(addParagraph("For instance, if you type YES, the first if statements compares this with the string \"YES\" and if they match, an appropriate message is logged. We then have a couple of else if clauses and the purpose of an else if clause is to try another test if the first one fails and here, that means testing for a value of \"MAYBE\" and then for a value of \"NO\".")); main.append(addParagraph("Finally we have an else clause. The else if and the else clauses are related to the original if statement and the name might give a clue as to how they work. In our example, we had typed \"YES\" and so the code associated with the if statement was executed since the values did match. Let's say we had typed something random (it doesn't matter what, just anything that isn't \"YES\", \"NO\" or \"MAYBE\". When we run the comparison in the id statement, it doesn't match and the JavaScript interpreter then checks to see if there is an if or an else if clause.")); main.append(addParagraph("It finds an else if clause but the strings again don't match so it looks for another and finds the second else if clause, the strings still don't match so it looks again. This time, it doesn't find another comparison operator, just an else clause and this is an unconditional clause so if the interpreter reaches it, the code in that clause is going to be executed.")); main.append(addParagraph("Essentially the code is saying do this if answer has a value of \"YES\", do this if answer has a value of \"MAYBE\", do this if answer has a value of \"NO\" and finally do this if answer doesn't have any of the values tested for.")); main.append(addParagraph("The very simplest form of an if statement is")); main.append(addSyntax("if (condition) do_this();")); main.append(addParagraph("This just tests a value and runs the code if the condition evaluates to true. The next simplest form would add an else clause ")); main.append(addSyntax("if (condition) do_this() else do_that()")); main.append(addParagraph("This expands on the first version by adding the else clause so now we don't just do something if the condition evaluates to true, the code in the else clause is executed if it evaluates to false.")); main.append(addParagraph("In our example, we also had a couple of else if clauses so now, rather than running the code in the else clause if the condition evaluates to false, we will run the code in that clause if and only if, the condition in the if clause and the conditions in the else if clauses all evaluate to false.")); main.append(addParagraph("If any of these conditions evaluate to true, the associated clause is executed and we then don't execute any other else clause, including the else if clauses (if there are any left).")); main.append(addParagraph("One final thing to mention, and again this is something that JavaScript has in common with other programming languages and that is you can nest if statements and this is the opposite of using an else if clause. The if statement in an else clause is evaluated only if the associated if clause returns a false value (and there are no other if else clauses that have already been evaluated that returned a true value.")); main.append(addParagraph("If you nest an if statement inside another if statement, the result is that if the outer statement retrurns true, the inner statement is also going to be evaluated whereas if it is false, it won't be evaluated. The following example might make this clearer.")); main.append(addInsetCodeListing(["let a = 1;", "", "if (a) {", " console.log(\"A exists or is true\");", "} else if (!a) {", " console.log(\"A doesn't exist or is false\");", "}"])); main.append(addParagraph("In this example, the value of a is checked and since we set it to 1, it will return a true value and we get the output, \"A exists or is true\" and the conditional in the if else clause is not evaluated.")); main.append(addParagraph("The second if statement is not really required since we don't need to test if a doesn't have a value. This is because we would only test that if the first condition had failed which would tell us that it doesn't have a value (technically, I should say doesn't have a value that will evaluate to true when tested like this) so we are really running the same test twice!")); main.append(addParagraph("Let's look at another example which is even more pointless.")); main.append(addInsetCodeListing(["let a = 1;", "", "if (a) {", " if (!a) {", " console.log(\"Something weird is going on here!\");", " }", "}"])); main.append(addParagraph("Again, we start by testing a, if it is true we then run the second test on a. If it is false, the output is sent to the console. This is pointless, because we only log that output if a is false and we only test for that if a is true so it is depending on a being both true and false at the same time. In reality, you would only ever use a construct like this if you had some code that you want to execute only if two conditions are met. For example, if we have two variables called a and b, and we want to execute some code if both variables return true values, we could nest the test for inside a test for the other.")); main.append(addParagraph("Of course, you can do the same thing by sampling testing both in a single conditional such as")); main.append(addParagraph("if (a && b)")); main.append(addParagraph("Although this might sound counterintuitive, you can also achieve the same thing using an if else clause. To do that, your if clause would test a like this")); main.append(addParagraph("if (!a)")); main.append(addParagraph("We can then have the test")); main.append(addParagraph("if (b)")); main.append(addParagraph("in the if else clause. This would achieve the same thing because remember that the else if clause is only evaluated if the first condition is false and since we used the negation operator, it will return false if a is true so the second condition is only tested if a is true and so the result is the same.")); main.append(addParagraph("Conditionals: switch")); main.append(addParagraph("We saw with the if statement that when your logic gets quite complicated and you have multiple conditions, there are different ways to do this and the choice of one method over another depends largely on circumstances so there is no one best method.")); main.append(addParagraph("If you are checking one variable and want to execute some code depending on the value it has taken, there is also another way to handle this and that is with a switch statement. An example of this is shown below.")); main.append(addImageWithCaption("./images/switch.png", "The syntax of a switch statement in JavaScript.")); main.append(addParagraph("The variable we are testing os answer but the value we are testing it for is not in the conditional statement (the switch statement in the first line). Each case statement specifies a value that variable might take and the code that you want to execute if it does.")); main.append(addParagraph("This is a neater version of code we saw earlier where we had an if statement testing whether answer had a value of \"YES\". We also had else if clauses to test for other possible answers and an else clause to cover any other possibilities (ie, it specifies the code to be executed in this case if the value isn't one of the ones we expect and therefore don't test for it).")); main.append(addParagraph("One important point is that when a case specifies a value that matches the value of answer, the interpreter will then execute the code in that case and any other code until it reaches the end of the code block or encounters a break statement which causes the interpreter to end execution.")); main.append(addParagraph("For example, if answer has the value \"YES\", we would log an appropriate response to the console and the break statement tells the switch statement to end so we don't execute the code associated with the other cases. If we omitted these, we would see four messages logged to the console so these break statements are very important and typically you will find one at the end of each case statement (or block).")); main.append(addParagraph("The default clause again covers all possible answers we don't explicitly test for and so it is equivalent to the earlier else clause.")); main.append(addParagraph("The syntax for switch is standard and you will find that this code would work equally well in Java or C/C++ and most likely in any programming language that supports switch.")); main.append(addParagraph("Terse ifs: One Liners")); main.append(addParagraph("We have seen various forms of the if statement but in most cases, you will see that the condition is followed by a code block within curly braces. This allows us to associate more than one line of code with the condition. In general, where you have a statement like")); main.append(addParagraph("if (condition) {}")); main.append(addParagraph("where the code within the curly braces is executed when the condition evaluates to true. The same is true for an if else clause or an else clause. The curly braces are not required, however, if there is only one statement and if that's the case, we can do something like this.")); main.append(addParagraph("if (condition) do_this() else do_that();")); main.append(addParagraph("If you do have only one statement after the condition, you can still include the curly braces and there are some advantages to doing that. It does (in my opinion) make the code a little bit easier to read and it is more flexible in that it allows you to add more statements later without having to remember that you may need to add the curly braces in. Take this example")); main.append(addInsetCodeListing(["if (condition) {", " do_this();", "} else {", " do_that();", "}"])); main.append(addParagraph("In this example, it is easier to see where each code block starts and ends and this is even more the case if you add in one or more else if clauses and it gives you more consistency if one or more of the clauses requires curly braces because there are multiple statements to be executed for that clause.")); main.append(addParagraph("We also saw previously that we can simply test a variable to see if it has a value and in general terms, if it does, this will essentially evaluate to true so")); main.append(addParagraph("If (a) {};")); main.append(addParagraph("will execute it's block of code if a has a value. Let's say we have an array of error messages and we want to log these if there are any (that is, if the array is not empty. You might expect to do it like this.")); main.append(addInsetCodeListing(["if (errors) {", " console.log(\"There are errors: \", errors);", "}"])); main.append(addParagraph("This is saying that if errors returns a true value, log this message to the console. We can test this with a node editor in a terminal by typing the command")); main.append(addParagraph(".editor")); main.append(addParagraph("to go into edit mode and this allows us to type in several lines of JavaScript code but it won't execute until we press Control and d. Enter the following lines of code")); main.append(addInsetCodeListing(["errors=[\"error1\", \"error2\", \"error3\"];", "if (errors) {", " console.log(\"There are errors: \", errors);", "}"])); main.append(addParagraph("and press Control d to execute it and this will give you the output")); main.append(addParagraph("There are errors [ 'error1', 'error2', 'error3' ]")); main.append(addParagraph("So that seems to work. However, if we try this again and this time the code is")); main.append(addInsetCodeListing(["errors=[];", "if (errors) {", " console.log(\"There are errors: \", errors);", "}"])); main.append(addParagraph("When you press Control and d, you will see this output")); main.append(addParagraph("There are errors")); main.append(addParagraph("This is because the array, errors, still has a value and although that value is an empty array, it is still enough for this to be evaluated as true. This means that the condition is meaningless because it will always evaluate to true if the array exists and will give you an error if it doesn't.")); main.append(addParagraph("In JavaScript, a value is considered to be truthy if it would give you a true value when used in place of a Boolean variable in a context such as the condition in an if statement and similarly, if it would give you a false value it would be considered to be falsy. ")); main.append(addParagraph("The MDN Web Docs provides more information with examples on both truthy and falsy values and on the truthy page, you can see that an empty arrays is considered to be truthy.")); main.append(addParagraph("You can resolve this by using a condition that would work as expected like this")); main.append(addInsetCodeListing(["errors=[];", "if (errors.length) {", " console.log(\"There are errors: \", errors);", "} else {", " console.log(\"There are no errors\");"])); main.append(addParagraph("If you press Control and d to execute this, you will get the output ")); main.append(addParagraph("There are no errors")); main.append(addParagraph("Rather than testing to see if the errors array exists (which it will if it is an empty array), we are checking to see if it has a length. If it is an empty array, the length will be 0 and this is a falsy value so the condition evaluates to false and the code in the else clause is executed.")); main.append(addParagraph("Terse ifs: Ternaries")); main.append(addParagraph("This is a shortened form of the if / else construction – that is, an if statement followed by an else clause with no else if clauses. Something like this")); main.append(addInsetCodeListing(["if (animal === cat) {", " console.log('You will be a cat herder.');", "} else {", " console.log('You will be a dog catcher.');", "}"])); main.append(addParagraph("With a ternary operator, we can condense this into a single line.")); main.append(addParagraph("if (animal === cat) ? console.log('You will be a cat herder.') : console.log('You will be a dog catcher.');")); main.append(addParagraph("The syntax is fairly simple. We have a condition and two actions. There is a question mark after the condition and a colon between the two actions. When this statement is executed, one (and only one) of these two actions will be performed, depending on the result of evaluating the condition.")); main.append(addParagraph("If the condition evaluates to true, the first action is performed. If it evaluates to false, the second action is performed.")); main.append(addParagraph("This is a pretty standard syntax and you will see that the ternary operator uses the same syntax in many other languages including C and its derivatives and Java.")); main.append(addParagraph("We can also skip the if statement and use the ternary operator to set the value of some variable depending on the result of evaluating a condition like this.")); main.append(addParagraph("var job = animal === 'cat' ? 'cat herder' : 'dog catcher';")); main.append(addParagraph("This will evaluate he condition and will return either 'cat herder' if the condition is true (if the value of animal is 'cat' or 'dog catcher' if the condition is false. You may not see ternary operators in use all that often, but this is a fairly typical usage.")); main.append(addParagraph("Type Checking")); main.append(addParagraph("JavaScript is pretty laid-back when it comes to data types and it won't complain if you have a variable with type number for example such as")); main.append(addParagraph("let thing = 12;")); main.append(addParagraph("which you later assign a different type of data to.")); main.append(addParagraph("thing = \"twelve\";")); main.append(addParagraph("As a result, you may find that you are working with a variable and you think that it should have one data type, but it actually has another. You might also want to execute one code block or another depending on what its data type is so it is important to be able to check that.")); main.append(addParagraph("In JavaScript, you can do that with the typeof operator as shown below.")); main.append(addImageWithCaption("./images/typeof.png", "Using the typeof operator to determine the date type of a variable.")); main.append(addParagraph("It's worth noting that typeof always returns a string containing the name of the data type and you can see that in the image shown above where it returned 'number' and then 'string'.")); main.append(addParagraph("Something to be wary of is that it is not always quite so easy to determine a data type. For example, let's say we have an array")); main.append(addParagraph("thing = []")); main.append(addParagraph("You might expect that")); main.append(addParagraph("typeof thing")); main.append(addParagraph("would return 'array' but it doesn't. Remember, arrays are objects in JavaScript and typeof is unable to distinguish it from any other object. However, there is an object method that is helpful here. We mentioned earlier that arrays have a length property and the object method, hasOwnProperty() can check if an object has a specified property. So")); main.append(addParagraph("typeof thing === 'object' a&& thing.hasOwnProperty('length')")); main.append(addParagraph("will return true if thing is an array or false if it isn't. This works by testing to see if thing is an object and if it is, it also tests whether it has a length property so if we get true back, we can say that thing is an object with a length property.")); main.append(addParagraph("As it happens, this is a property that an object will only have if it is an array so that's enough for us to identify thing as an array. Of course, there are some properties that will be common to a number of objects so not all properties can be used to identify the type of an object in this way!")); main.append(addParagraph("Something else that gives you a result with typeof that you may not expect is NaN (you may remember, this stands for Not a Number and is the response you will usually get when you try to perform an operation that expects a number and gets something else. If we do")); main.append(addParagraph("typeof(NaN);")); main.append(addParagraph("You might expect that to return something like object or maybe even string, but you probably wouldn't expect it to return number which is exactly what it will do. So, if you have a variable that should be a number but you want to check that it isn't NaN, type of isn't going to help you there. ")); main.append(addParagraph("However, JavaScript has a built-in object called Number and this has a method, isNaN() which we can use to check if something is indeed not a number. For example,")); main.append(addParagraph("Number.isNan(NaN);")); main.append(addParagraph("Will return true because NaN is not a number. If we try the same thing with something that is a number such as 127")); main.append(addParagraph("Number.isNan(127);")); main.append(addParagraph("the result will be false. You do need to be careful with this because it will only return true for something that returns NaN. If you just try this using a variable, it is only going to return true if the value of that variable is NaN so bear in mind, we are not testing to see if some variable has a value that is not a number, we are literally testing to see if the value is nan. For example")); main.append(addParagraph("Number.isNan(\"NaN\");")); main.append(addParagraph("will return false because although this value is not a number, it's a string containing NaN but it is not actually NaN.")); main.append(addParagraph(" Like an array, if you use type of to get the type of null, this will return an object which is a little bit strange, but JavaScript does seem to treat null as an object. The easiest way to check if something has a null value is with the strict equality operator rather than with typeof. so")); main.append(addParagraph("thing === null;")); main.append(addParagraph("will return true if thing has a null value!")); main.append(addParagraph("Something you will quickly see with typeof if you experiment with it or if you just use it a lot is that it will sometimes return undefined so it will do that with a variable you have defined but not initialised or with a variable that it doesn't recognise at all – in other words, where you haven't even created the variable yet.")); main.append(addParagraph("So JavaScript does provide some basic facilities for checking the type of a variable but it can be a little bit confusing sometimes so you do need to be careful with it and make full use of the documentation.")); main.append(addParagraph("There are some other alternatives. For example, you could use a JavaScript library such as Lodash which provides a lot of utility functions including many for checking various data types and you can get more information on these by searching for is in the Lodash Docs. Of course, you can also write your own functions for type checking.")); main.append(addParagraph("Perhaps a more extreme alternative is to use TypeScript. TypeScript is a superset of JavaScript and one of the features it adds is strict type checking.")); main.append(addParagraph("If you are just starting to learn JavaScript, typeof is probably going to be sufficient for your basic needs but just be aware that it does have some weaknesses and arguably its type-checking is one of those but JavaScript is designed to be easy to use and its lack of type checking is, in that context a strength. You should also know that there are other options which you may want to explore if you start to find JavaScript to be too limiting (or maybe too easy to use). With more experience, ease of use becomes less important and you may want to start looking at alternatives at that point.")); addSidebar("webdev");