| Sites: Javascript: Dictionary - 2 |
| 1 | * Operator precedence |
| 2 | ^ Description |
| 3 | a) if an expression has more than one operator, the execution order is defined by their precedence |
| 4 | b) or, in other words, the default priority order of operators |
| 5 | c) from school, we all know that the multiplication in the expression 1 + 2 * 2 should be calculated before the addition |
| 6 | `that's exactly the precedence thing |
| 7 | d) the multiplication is said to have a higher precedence than the addition |
| 8 | e) parentheses override any precedence, so if we aren't satisfied with the default order, we can use them to change it |
| 9 | `(1 + 2) * 2 |
| 10 | f) there are many operators in js |
| 11 | g) every operator has a corresponding precedence number |
| 12 | h) the one with the larger number executes first |
| 13 | ^ Description (part 2) |
| 14 | a) if the precedence is the same, the execution order is from left to right |
| 15 | b) here's an extract from the precedence table |
| 16 | `https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence |
| 17 | `we don't need to remember this, but note that unary operators are higher than corresponding binary ones |
| 18 | c) example |
| 19 | `unary plus + and unary negation are 17 precedence |
| 20 | `exponentiation ** is 16 precedence |
| 21 | `multiplication and division are 15 precedence |
| 22 | `addition and subtraction are 13 precedence |
| 23 | `assignment is 3 precedence |
| 24 | d) as we can see, the 'unary plus' has a priority of 17 which is higher than the 13 of 'addition' (binary plus) |
| 25 | e) that's why, in the expression "+apples + +oranges", unary pluses work before the addition |
| 26 | * Assignment |
| 27 | ^ Introduction |
| 28 | a) Let's note that an assignment = is also operator |
| 29 | b) it's listed in the precedence table with the very low priority of 3 |
| 30 | c) that's why, when we assign variable, like x = 2 * 2 + 1, the calculations are done first and then the = is evaluated, storing the result in x |
| 31 | `let x = 2 * 2 + 1; |
| 32 | `alert(x); // 5 |
| 33 | ^ Assignment = returns a value |
| 34 | a) the fact of = being an operator, not a 'magical' language construct has an interesting implication |
| 35 | b) all operators in js return a value |
| 36 | c) that's obvious for + and -, but also true for = |
| 37 | d) the cal x = value writes the value into x and then returns it |
| 38 | e) here's a demo that uses an assignment as part of a more complex expression |
| 39 | `let a = 1; |
| 40 | `let b = 2; |
| 41 | `let c = 3 - (a = b + 1); |
| 42 | `alert(a); // 3 |
| 43 | `alert(c); // 0 |
| 44 | f) in the example above, the result of expression (a = b + 1) is the value which was assigned to a (that is 3) |
| 45 | g) it is then used for further evaluations |
| 46 | h) funny code, isn't it? |
| 47 | ^ Assignment = returns a value (part 2) |
| 48 | a) we should understand how it works, because sometimes we see it in js libraries |
| 49 | b) although, please don't write the code like that |
| 50 | c) such tricks definitely don't make code clearer or readable |
| 51 | ^ Chaining Assignments |
| 52 | a) another interesting feature is the ability to chain assignments |
| 53 | `let a, b, c; |
| 54 | `a = b = c = 2 + 2; |
| 55 | `alert(a); // 4 |
| 56 | `alert(b); // 4 |
| 57 | `alert(c); // 4 |
| 58 | b) chained assignments evaluate from right to left |
| 59 | c) first, the rightmost expression 2 + 2 is evaluated and then assigned to the variables on the left: c, b and a |
| 60 | d) at the end, all the variables share a single value |
| 61 | e) once again, for the purposes of readability it's better to split such code into few lines |
| 62 | `c = 2 + 2; |
| 63 | `b = c; |
| 64 | `a = c; |
| 65 | f) that's easier to read, especially when eye-scanning the code fast |
| 66 | ^ Modify-in-place |
| 67 | a) we often need to apply an operator to a variable and store the new result in that same variable |
| 68 | b) example |
| 69 | `let n = 2; |
| 70 | `n = n + 5; |
| 71 | `n = n * 2; |
| 72 | c) this notation can be shortened using the operators += an *= |
| 73 | `let n = 2; |
| 74 | `n += 5; // now n = 7 (same as n = n + 5) |
| 75 | `n *= 2; // now n = 14 (same as n = n * 2) |
| 76 | d) short 'modify-and-assign' operator exist for all arithmetical and bitwise operators |
| 77 | `/= |
| 78 | `-= |
| 79 | e) such operators have the same precedence as a normal assignment, so they run after most other calculations |
| 80 | `let n = 2; |
| 81 | `n *= 3 + 5; |
| 82 | `alert(n); // 16 right part evaluated first, same as n *= 8 |
| 83 | * Increment/Decrement |
| 84 | ^ Introduction |
| 85 | a) increasing or decreasing a number by one is among the most common numerical operations |
| 86 | b) there are special operators for it |
| 87 | c) Increment '++' increases a variable by 1 |
| 88 | `let counter = 2; |
| 89 | `counter++; // works the same as counter = counter + 1, but is shorter |
| 90 | `alert(counter); // 3 |
| 91 | d) Decrement '--' decreases a variable by 1 |
| 92 | `let counter = 2; |
| 93 | `counter--; // works the same as counter = counter - 1, but is shorter |
| 94 | `alert(counter); // 1 |
| 95 | ^ Important |
| 96 | a) increment/decrement can only be applied to variables |
| 97 | b) trying to use it on values like 5++ will give an error. |
| 98 | c) the operators ++ and -- can be placed either before or after a variable |
| 99 | `when the operators goes after the variable, it is in 'postfix form' |
| 100 | ,counter++ |
| 101 | `the 'prefix form' is when the operator goes before the variable |
| 102 | ,++counter |
| 103 | d) both of these statements do the same thing: increase counter by 1 |
| 104 | e) is there any difference? yes, but we can only see it if we use the returned value of ++/-- |
| 105 | f) let's clarify. as we know, all operators return a value |
| 106 | g) increment/decrement is no exception |
| 107 | h) the prefix form returns the new value while the postfix form returns the old value |
| 108 | `prior to increment/decrement |
| 109 | ^ Important (part 2) |
| 110 | a) to see the difference, here's an example |
| 111 | `let counter = 1; |
| 112 | `let a = ++counter; // (*) |
| 113 | `alert(a); // 2 |
| 114 | b) in the line (*), the prefix form ++counter increments counter and returns the new value, 2. |
| 115 | `so, the alert shows 2 |
| 116 | c) now, let's use the postfix form |
| 117 | `let counter = 1; |
| 118 | `let a = counter++; |
| 119 | `alert(a); // 1 |
| 120 | d) in the line (*), the postfix form counter++ also increments counter but returns the old value (prior to increment) |
| 121 | `so, the alert shows 1 |
| 122 | ^ Summarize |
| 123 | a) if the result of increment/ decrement is not used, there's no difference in which form to use |
| 124 | `let counter = 0; |
| 125 | `counter++; |
| 126 | `++counter; |
| 127 | `alert(counter); // 2 the lines above did the same |
| 128 | b) if we'd like to increase a value and immediately use the result of the operator, we need the prefix form |
| 129 | `let counter = 0; |
| 130 | `alert(++counter); // 1 |
| 131 | c) if we'd like to increment a value but use its previous value, we need the postfix form |
| 132 | `let counter = 0; |
| 133 | `alert(counter++); // 0 |
| 134 | ^ Increment/Decrement among other operators |
| 135 | a) the operators ++/-- can be used inside expressions as well |
| 136 | b) their precedence is higher than most other arithmetical operations |
| 137 | `let counter = 1; |
| 138 | `alert(2 * ++counter); // 4 |
| 139 | c) compare with |
| 140 | `let counter = 1; |
| 141 | `alert(2 * counter++); // 2, because counter++ returns the old value |
| 142 | d) though technically okay, such notation usually makes code less readable |
| 143 | e) one line does multiple things - not good |
| 144 | f) while reading code, a fast 'vertical' eye-scan can easily miss sth like counter++ and it won't be obvious that the variable increased |
| 145 | g) we advise a style of 'one line - one action' |
| 146 | `let counter = 1; |
| 147 | `alert(2 * counter); |
| 148 | `counter++; |
| 149 | ^ Bitwise operators |
| 150 | a) bitwise operators treat arguments as 32-bit integer numbers and work on the level of their binary representation |
| 151 | b) these operators are not js-specific |
| 152 | c) they're supported in most programme languages |
| 153 | d) the list of operators |
| 154 | `AND (&) |
| 155 | `OR (|) |
| 156 | `XOR (^) |
| 157 | `NOT (~) |
| 158 | `LEFT SHIFT (<<) |
| 159 | `RIGHT SHIFT (>>) |
| 160 | `ZERO-FILL RIGHT SHIFT (>>>) |
| 161 | e) these operators are used very rarely, when we need to fiddle on the very lowest (bitwise) level. |
| 162 | f) we won't need these operators any time soon, as web development has little use of them, but in some special areas, such as cryptography, they're useful |
| 163 | * Comma |
| 164 | ^ Introduction |
| 165 | a) the comma operator ',' is one of the rarest and most unusual operators |
| 166 | b) sometimes, it's used to write shorter code, so we need to know it in order to understand what's going on |
| 167 | `let a = (1 + 2, 3 + 4); |
| 168 | `alert(a); // 7 (the result of 3 + 4) |
| 169 | c) here the first expression 1 + 2 is evaluated and its result is thrown away |
| 170 | d) then, 3 + 4 is evaluated and returned as the result |
| 171 | ^ Comma has a very low precedence |
| 172 | a) please note that the comma operator has very low precedence |
| 173 | `lower than = |
| 174 | b) so parentheses are important in the example above |
| 175 | c) without them a = 1 + 2, 3 + 4 evaluates + first, summing the numbers into a = 3, 7 |
| 176 | `then, the assignment operator = assigns a = 3, and the rest is ignored |
| 177 | d) it's like (a = 1 + 2), 3 + 4 |
| 178 | e) why do we need an operator that throws away everything except the last expression? |
| 179 | f) sometimes, people use it in more complex constructs to put several actions in one line |
| 180 | `// three operations in one line |
| 181 | `for (a = 1, b = 3, c = a * b; a < 10; a++) { |
| 182 | `... |
| 183 | `} |
| 184 | g) such tricks are used in many js frameworks |
| 185 | h) that's why we're mentioning them |
| 186 | `but usually they don't improve code readability so we should think well before using them |
| 187 | * Tasks Basic operators, maths |
| 188 | ^ The postfix and prefix forms |
| 189 | a) what are the final values of all variables a, b, c and d after the code below |
| 190 | `let a = 1, b = 1; |
| 191 | `let c = ++a; // 2 prefix form returns the new value |
| 192 | `let d = b++; // 1 postfix form returns the old value |
| 193 | ^ Assignment result |
| 194 | a) what are the values of a and x after the code below |
| 195 | `let a = 2; |
| 196 | `let x = 1 + (a *= 2); // 5 calculated as 1 + 4 |
| 197 | ^ Type Conversions |
| 198 | a) what are results of these expressions? |
| 199 | `"" + 1 + 0; // '10' the addition "" + 1 converts to '1', then '1' + 0 = '10' |
| 200 | `"" - 1 + 0; // -1 the subtraction (like most math operations) only works with numbers, it converts an empty string "" to 0 |
| 201 | `true + false; // 1 |
| 202 | `6 / '3'; // 2 |
| 203 | `"2" * "3"; // 6 |
| 204 | `4 + 5 + 'px'; // '9px' |
| 205 | `"$" + 4 + 5; // '$45' |
| 206 | `"4px" - 2; // NaN |
| 207 | `"4" - 2; // 2 |
| 208 | `" -9 " + 5; // -9 5 |
| 209 | `" -9 " - 5; // -14 the subtraction always converts to numbers, so it makes ' -9 ' a number -9 (ignoring spaces around it) |
| 210 | `null + 1; // 1 null becomes 0 after the numeric conversion |
| 211 | `undefined + 1; // NaN (undefined becomes NaN after the numeric conversion |
| 212 | `" \t " - 2; // space characters, are trimmed off string start and end when a string is converted to a number. |
| 213 | ,here the whole string consists of space characters, such as \t, and a 'regular' space between them |
| 214 | ,so, similarly to an empty string, it becomes 0 |
| 215 | ^ Fix the addition |
| 216 | a) here's a code that asks the user for two numbers and shows their sum |
| 217 | b) it works incorrectly. The output in the example below is 12 (for default prompt values) |
| 218 | c) why? Fix it. The result should be 3 |
| 219 | `let a = prompt('First number?', 1); // fix let a = +prompt... |
| 220 | `let b = prompt('Second number?', 2); // fix let b = +prompt... |
| 221 | `alert(a + b); // or alert(+a + +b); or alet(Number(a) + Number(b)); |
| 222 | c) explanation |
| 223 | `the reason is that prompt returns user input as a string |
| 224 | `so variables have values '1' and '2' respectively |
| 225 | `what we should do is to convert strings to numbers before + |
| 226 | ,for example, using Number() or prepending them with + |
| 227 | * from Comment Basic Operators, maths |
| 228 | ^ difference between postfix and prefix |
| 229 | a) the difference between ++z and z++ is only when one of these expressions is included in an other expression |
| 230 | `z = 0; |
| 231 | `z++; |
| 232 | `alert(z); // 1 no difference between z++ and ++z |
| 233 | b) but if we include now theses expressions in another one (alert for example) then we can see the difference |
| 234 | `let z = 0; |
| 235 | `alert(z++); // 0 difference as alert(++z) is 1 |
| 236 | * Comparisons |
| 237 | ^ Introduction |
| 238 | a) we know many comparisons from maths |
| 239 | b) in js they're written like this |
| 240 | `greater/less than: a > b, a < b |
| 241 | `greater/less than or equals: a >= b, a <= b |
| 242 | `equals: a == b |
| 243 | ,please note the double equality sign == means the equality test |
| 244 | ,while a single one = means an assignment |
| 245 | `not equals: in maths the notation is crossed out sign of equality |
| 246 | `but in js it's written a != b |
| 247 | c) in this article we'll learn more about different types of comparisons, how js makes them, including important |
| 248 | d) at the end you'll find a good recipe to avoid 'js quirks' - related issues |
| 249 | ^ Boolean is the result |
| 250 | a) all comparison operators return a boolean value |
| 251 | `true - means 'yes', 'correct' or 'the truth' |
| 252 | `false - means 'no', 'wrong' or 'not the truth' |
| 253 | b) example |
| 254 | `alert(2 > 1); // true (correct) |
| 255 | `alert(2 == 1); // false (wrong) |
| 256 | `alert(2 != 1); // true (correct) |
| 257 | c) a comparison result can be assigned to a variable, just like any value |
| 258 | `let result = 5 > 4; // assign the result of the comparison |
| 259 | `alert(result); // true |
| 260 | ^ String comparison |
| 261 | a) to see whether a string is greater than another, js uses the so-called 'dictionary' or 'lexicographical' order |
| 262 | `in other words, strings are compared |
| 263 | b) example |
| 264 | `alert('Z' > 'A'); // true |
| 265 | `alert('Glow' > 'Glee'); // true |
| 266 | `alert('Bee' > 'Be'); // true |
| 267 | c) the algorithm to compare two strings is simple |
| 268 | `compare the first character of both strings |
| 269 | `if the first character from the first string is greater (or less) than the other string's |
| 270 | ,the first string is greater (or less) than the second |
| 271 | `otherwise, if both string's first characters are the same, compare the second characters the same way |
| 272 | `repeat until the end of either string |
| 273 | `if both strings end at the same length, then they're equal |
| 274 | ,otherwise, the longer string is greater |
| 275 | d) in the first example above, the comparison 'Z' > 'A' gets to a result at the first step |
| 276 | e) the second comparison 'Glow' and 'Glee' needs more steps as strings are compared character-by-character |
| 277 | `G is the same as G |
| 278 | `l is the same as l |
| 279 | `o is greater than e. |
| 280 | ,stop here, the first string is greater |
| 281 | * Not a real dictionary, but Unicode order |
| 282 | a) the comparison algorithm given above is roughly equivalent to the one used in dictionaries or phone books, but it's not exactly the same |
| 283 | b) for instance, case matters. |
| 284 | `a capital letter 'A' is not equal to the lowercase 'a' |
| 285 | ,because the lowercase character has a greater index in the internal encoding table js uses (Unicode) |
| 286 | * Comparison of different types |
| 287 | a) when comparing values of different types, js converts the values to numbers |
| 288 | `alert('2' > 1); // true, string '2' becomes a number 2 |
| 289 | `alert('01' == 1); // true, string '01' becomes a number 1 |
| 290 | b) for boolean values, true becomes 1 and false becomes 0 |
| 291 | `alert(true == 1); // true |
| 292 | `alert(false == 0); // true |
| 293 | ^ A funny consequence |
| 294 | a) it's possible that at the same time |
| 295 | `two values are equal |
| 296 | `one of them is true as a boolean and the other one is false as a boolean |
| 297 | b) example |
| 298 | `let a = 0; |
| 299 | `alert(Boolean(a)); // false |
| 300 | `let b = '0'; |
| 301 | `alert(Boolean(b)); // true |
| 302 | `alert(a == b); // true |
| 303 | c) from js's standpoint, this result is quite normal |
| 304 | d) an equality check converts values using the numeric conversion |
| 305 | `hence '0' becomes 0, while the explicit Boolean conversion uses another set of rules |
| 306 | * Strict equality |
| 307 | a) a regular equality check == has a problem. |
| 308 | `it can't differentiate 0 from false |
| 309 | b) the same thing happens with an empty string |
| 310 | `alert("" == false); // true |
| 311 | c) this happens because operands of different types are converted to numbers by the equality operator ==. |
| 312 | d) an empty string, just like false, becomes a zero. |
| 313 | e) what to do if we'd like to differentiate o from false? |
| 314 | f) a strict equality operator === checks the equality without type conversion |
| 315 | `in other words, if a and b are of different types, then a === b immediately returns false without an attempt to convert them |
| 316 | g) let's try it |
| 317 | `alert(0 === false); // false, because the types are different |
| 318 | h) there's also a strict non-equality operator !== analogous to != |
| 319 | * Comparison with null and undefined |
| 320 | ^ Introduction |
| 321 | a) there's a non-intuitive behaviour when null or undefined are compared to other values |
| 322 | b) for a strict equality check === |
| 323 | `these values are different, because each of them is a different type |
| 324 | ,alert(null === undefined); // false |
| 325 | c) for a non-strict check == |
| 326 | `there's a special rule |
| 327 | `these two are 'sweet couple', but not any other value |
| 328 | ,alert(null == undefined);; // true |
| 329 | d) for maths and other comparisons < > <= >= |
| 330 | `null/undefined are converted to numbers |
| 331 | ,null becomes 0 |
| 332 | ,undefined becomes NaN |
| 333 | * Strange result: Null vs 0 |
| 334 | a) Let's compare null with a zero |
| 335 | `alert(null > 0); // false |
| 336 | `alert(null == 0); // false |
| 337 | `alert(null >= 0); // true |
| 338 | b) Mathematically, that's strange |
| 339 | `the last result states 'null is greater than or equal to zero' |
| 340 | `so in one of the comparisons above it must be true, but they're both false |
| 341 | c) The reason is that an equality check == and comparisons > < >= <= work differently |
| 342 | d) Comparisons convert null to a number, treating it as 0 |
| 343 | e) That's why null >= 0 is true and null > 0 is false |
| 344 | f) On the other hand, the equality check == for undefined and null is defined such that, without any conversions |
| 345 | `they equal each other and don't equal anything else |
| 346 | `that's why null == 0 is false |
| 347 | * An incomparable undefined |
| 348 | a) The value undefined shouldn't be compared to other values |
| 349 | `alert(undefined > 0); // false (1) |
| 350 | `alert(undefined < 0); // false (2) |
| 351 | `alert(undefined == 0); // false (3) |
| 352 | b) Why does it dislike zero so much? Always false! |
| 353 | c) We get these results because |
| 354 | `Comparisons (1) and (2) return false because undefined gets converted to NaN and NaN is a special numeric value which returns false for all comparisons |
| 355 | `The equality check (3) returns false because undefined only equals |
| 356 | ,null |
| 357 | ,undefined |
| 358 | ^ Avoid problems |
| 359 | a) Why did we go over these examples? |
| 360 | `Should we remember these peculiarities all the time? |
| 361 | `Well, not really |
| 362 | `Actually, these tricky things will gradually become familiar over time, but there's a solid way to avoid problems with them |
| 363 | b) Avoid problems |
| 364 | `Treat any comparison with undefined/null except the strict equality === with exceptional care |
| 365 | `Don't use comparisons >= > < <= with a variable which may be null/undefined, unless you're really sure of what you're doing |
| 366 | ,If a variable can have these values, check for them separately |
| 367 | * Summary |
| 368 | a) Comparison operators return a boolean value |
| 369 | b) Strings are compared letter-by-letter in the 'dictionary' order |
| 370 | c) When values of different types are compared, they get converted to numbers |
| 371 | `with the exclusion of a strict equality check |
| 372 | d) The values null and undefined equal == each other and don't equal any other value |
| 373 | e) Be careful when using comparisons like > or < with variables that can occasionally be null/undefined |
| 374 | `Checking for null/undefined separately is a good idea |
| 375 | * Tasks (Comparisons) |
| 376 | a) What will be the result for these expressions? |
| 377 | `5 > 4; // true |
| 378 | `"apple" > "pineapple"; // false (Dictionary comparison where 'a' is smaller than 'p' |
| 379 | `"2" > "12"; // true (Dictionary comparison where '2' is greater than '1') |
| 380 | `undefined == null; // true (values null and undefined equal each other) |
| 381 | `undefined === null; // false (Strict equality is strict. Different types from both sides lead to false) |
| 382 | `null == " 0 "; // false (null only equals to undefined) |
| 383 | `null === +" 0 "; // false (strict equality of different types) |
| 384 | * Conditional branching: if, '?' |
| 385 | ^ Introduction |
| 386 | a) Sometimes, we need to perform different actions based on different conditions |
| 387 | b) To do that, we can use the 'if' statement and the conditional operator '?', that's also called a 'question mark' operator |
| 388 | ^ The 'if' statement |
| 389 | a) The if(...) statement evaluates a condition in parentheses and, if the result is true, executes a block of code |
| 390 | `let year = prompt('In which year was ECMAScript-2015 specification published?', ""); |
| 391 | `if (year == 20156) alert('You are right!'); |
| 392 | b) In the example above, the condition is a simple equality check (year == 2015), but it can be much more complex |
| 393 | c) If we want to execute more than one statement, we have to wrap our code block inside curly braces |
| 394 | `if (year == 2015) { |
| 395 | `alert('That's correct!'); |
| 396 | `alert('You're so smart!'); |
| 397 | `} |
| 398 | d) We recommend wrapping your code block with curly braces {} every time you use an 'if' statement |
| 399 | `even if there's only one statement to execute |
| 400 | `doing so improves readability |
| 401 | * Boolean conversion |
| 402 | ^ Introduction |
| 403 | a) The if(...) statement evaluates the expression in its parentheses and converts the result to a boolean |
| 404 | b) Let's recall the conversion rules from the chapter Type Conversions |
| 405 | `A number 0, an empty string "", null, undefined and NaN all become false |
| 406 | ,Because of that they're called 'falsy' values |
| 407 | `Other values become true |
| 408 | ,so they're called 'truthy' |
| 409 | c) So, the code under this condition would never execute |
| 410 | `if (0) { // 0 is falsy |
| 411 | `... |
| 412 | `} |
| 413 | d) And inside this condition - it always will |
| 414 | `if (1) { // 1 is truthy |
| 415 | `... |
| 416 | `} |
| 417 | e) We can also pass a pre-evaluated boolean value to 'if', like this |
| 418 | `let cond = (year == 2015); // equality evaluates to true or false |
| 419 | `if (cond) { |
| 420 | `... |
| 421 | `} |
| 422 | * The 'else' clause |
| 423 | ^ Introduction |
| 424 | a) The if statement may contain optional 'else' block. |
| 425 | `it executes when the condition is falsy. |
| 426 | b) Example |
| 427 | `let year = prompt('In which year was the ECMAScript-2015 specification published?', ""); |
| 428 | `if (year == 2015) { |
| 429 | `alert('You guessed it right!); |
| 430 | `} else { |
| 431 | `alert('How can you be so wrong?'); // any value except 2015 |
| 432 | `} |
| 433 | * Several conditions: 'else if' |
| 434 | ^ Introduction |
| 435 | a) Sometimes, we'd like to test several variants of a condition |
| 436 | b) The 'else if' clause lets us do that |
| 437 | `let year = prompt('In which year was the ECMAScript-2015 published?', ""); |
| 438 | `if (year < 2015) { |
| 439 | `alert('Too early!'); |
| 440 | `} else if (year > 2015) { |
| 441 | `alert('Too late!'); |
| 442 | `} else { |
| 443 | `alert('Exactly!'); |
| 444 | `} |
| 445 | c) In the code above JavaScript first checks year < 2015 |
| 446 | `If that is falsy, it goes to the next condition year > 2015 |
| 447 | `If that is also falsy, it shows the last alert |
| 448 | d) There can be more else if blocks. |
| 449 | `The final else is optional |
| 450 | * Conditional operator '?' |
| 451 | a) Sometimes, we need to assign a variable depending on a condition |
| 452 | `let accessAllowed; |
| 453 | `let age = prompt('How old are you, ""); |
| 454 | `if (age > 18) { |
| 455 | `accessAllowed = true; |
| 456 | `} else { |
| 457 | `accessAllowed =false; |
| 458 | `} |
| 459 | `alert('accessAllower'); |
| 460 | b) The so-called 'conditional' or 'question mark' operator lets us do that in a shorter and simpler way |
| 461 | c) The operator is represented by a question mark '?' |
| 462 | `Sometimes, it's called 'ternary', because the operator has three operands |
| 463 | `It's actually the one and only operator in js which has that many |
| 464 | d) The syntax is |
| 465 | `let result = condition ? value1 : value2; |
| 466 | e) The condition is evaluated |
| 467 | `If it's truthy then value1 is returned, otherwise - value2 |
| 468 | f) Example |
| 469 | `let accessAllowed = (age > 18) ? true : false; |
| 470 | `Technically, we can omit the parentheses around age > 18 |
| 471 | `The question mark operator has a low precedence |
| 472 | ,so it executes after the comparison > |
| 473 | ^ Conditional operator '?' (part 2) |
| 474 | a) This example will do the same thing as the previous one |
| 475 | `// the comparison operator 'age > 18' executes first anyway |
| 476 | `// no need to wrap it into parentheses |
| 477 | `let accessAllowed = age > 18 ? true : false; |
| 478 | b) But parentheses make the code more readable, so we recommend using them |
| 479 | ^ Please note |
| 480 | a) In the example above, you can avoid using the question mark operator because the comparison itself returns true/false |
| 481 | `// the same |
| 482 | `let accessAllowed = age > 18; |
| 483 | * Multiple '?' |
| 484 | a) A sequence of question mark operators '?' can return a value that depends on more than one condition |
| 485 | `let age = prompt('age?', 18); |
| 486 | `let message = (age < 3) ? 'Hi, baby!' : |
| 487 | `(age < 18) ? 'Hello!' : |
| 488 | `(age < 100) ? 'Greetings!' : |
| 489 | `'What an unusual age!'; |
| 490 | `alert(message); |
| 491 | b) It may be difficult at first to grasp what's going on |
| 492 | `but after a closer look, we can see that it's just an ordinary sequence of tests |
| 493 | c) Explanation |
| 494 | `The first question mark checks whether age < 3 |
| 495 | `If true - it returns 'Hi, baby!'. |
| 496 | ,otherwise, it continues to the expression after the colon ':', checking age < 18 |
| 497 | `If that's true - it returns 'Hello!' |
| 498 | ,otherwise, it continues to the expression after the colon ':', checking age < 18 |
| 499 | `It that's true - it returns 'Greetings!' |
| 500 | ,otherwise, it continues to the expression after the colon ':', returning 'What an unusual age!' |
| 501 | d) Here's how this looks using if...else |
| 502 | `if (age < 3) { |
| 503 | `message = 'Hi, baby!'; |
| 504 | `} else if (age < 18) { |
| 505 | `message = 'Hello!'; |
| 506 | `} else if (age < 100) { |
| 507 | `message = 'Greetings!'; |
| 508 | `} else { |
| 509 | `message = 'What an unusual age!'; |
| 510 | `} |
| 511 | * Non-traditional use of '?' |
| 512 | a) Sometimes the question mark '?' is used as a replacement for 'if' |
| 513 | `let company = prompt('Which company created js?', ""); |
| 514 | `(company == 'Netscape') ? |
| 515 | `alert('Right!') : alert('Wrong!'); |
| 516 | b) Depending on the condition company == 'Netscape', either the first or the second expression after the '?' gets executed and shows an alert |
| 517 | c) We don't assign a result to a variable here |
| 518 | `Instead, we execute different code depending on the condition |
| 519 | d) It's not recommended to use the question mark operator in this way |
| 520 | e) The notation is shorter than the equivalent 'if' statement, which appeals to some programmers |
| 521 | `But it is less readable |
| 522 | f) Here's the same code using of comparison |
| 523 | `let company = prompt('Which company created js?', ""); |
| 524 | `if (company == 'Netscape') { |
| 525 | `alert('Right'); |
| 526 | `} else { |
| 527 | `alert('Wrong'); |
| 528 | `} |
| 529 | g) Our eyes scan the code vertically |
| 530 | `Code blocks which span several lines are easier to understand than a long, horizontal instruction set |
| 531 | h) The purpose of the question mark operator '?' is to return one value or another depending on its condition |
| 532 | `please use it for exactly that |
| 533 | `use 'if' when you need to execute different branches of code |
| 534 | * Tasks (Conditional branches 'if', '?') |
| 535 | ^ if (a string with zero) |
| 536 | a) Will alert be shown? |
| 537 | `if ('0') { |
| 538 | `alert('Hello'); |
| 539 | `} |
| 540 | b) '0' is not empty, so it will be true |
| 541 | ^ The name of js |
| 542 | a) Using the if... else construct, write the code which asks |
| 543 | `"What is the official name of JavaScript?" |
| 544 | `If the visitor enters 'ECMAScript', then output 'Right' |
| 545 | ,otherwise - output: "You don't know? ECMAScript!" |
| 546 | ^ Show the sign |
| 547 | a) Using if...else, write the code which gets a number via prompt and then shows in alert |
| 548 | `1, if the value is greater than zero |
| 549 | `-1, if less than zero |
| 550 | `0, if equals zero |
| 551 | b) In this task we assume that the input is always a number |
| 552 | ^ Rewrite 'if' into '?' |
| 553 | a) Rewrite this 'if' using a conditional operator '?' |
| 554 | `let result; |
| 555 | `if (a + b < 4) { |
| 556 | `result = 'Below'; |
| 557 | `} else { |
| 558 | `result = 'Over'; |
| 559 | `} |
| 560 | ^ Rewrite 'if...else' into '?' |
| 561 | a) Rewrite 'if...else' using multiple ternary operators '?' |
| 562 | b) For readability, it's recommended to split the code into multiple lines |
| 563 | `let message; |
| 564 | `if (login == 'Employee') { |
| 565 | `message = 'Hello'; |
| 566 | `} else if (login == 'Director') { |
| 567 | `message = 'Greetings'; |
| 568 | `} else if (login == "") { |
| 569 | `message = 'No login'; |
| 570 | `} else { |
| 571 | `message = ""; |
| 572 | `} |
| 573 | * Logical Operators |
| 574 | ^ Introduction |
| 575 | a) There are four logical operators in JS |
| 576 | `|| OR |
| 577 | `&& AND |
| 578 | `! NOT |
| 579 | `?? NULLISH COALESCING |
| 580 | b) Here we cover the first three |
| 581 | c) Although they're called "logical", they can be applied to values of any type, not only boolean. |
| 582 | , Their result can also be of any type. |
| 583 | ^ || OR |
| 584 | a) the OR operator is represented with two vertical line symbols |
| 585 | ,result = a || b; |
| 586 | b) In classical programming the logical OR is meant to manipulate boolean values only. |
| 587 | c) If any of its arguments are true, it returns true, otherwise false |
| 588 | d) In JS, the operator is a little bit trickier and more powerful. |
| 589 | `But first, let's see what happens with boolean values. |
| 590 | e) There are four possible logical combinations |
| 591 | `alert (true || true); // true |
| 592 | `alert (true || false); // true |
| 593 | `alert (false || true); // true |
| 594 | `alert (false || false); // false |
| 595 | f) As we can see, the result is always true except for the case when both operands are false |
| 596 | g) If an operand is not a boolean, it's converted to a boolean for the evaluation |
| 597 | h) For instance, the number 1 is treated as true, the number 0 as false |
| 598 | `if (1 || 0) { // works just like if (true || false) |
| 599 | `alert ( 'truthy!' ); |
| 600 | `} |
| 601 | ^ || OR (part 2) |
| 602 | a) Most of the time, OR || is used in an if statement to test if any of the given conditions is true |
| 603 | `let hour = 9; |
| 604 | `if (hour < 10 || hour > 18) { |
| 605 | `alert ( 'The office is closed.' ); |
| 606 | `} |
| 607 | b) We can pass more conditions |
| 608 | `let hour = 12; |
| 609 | `let isWeekend = true; |
| 610 | `if (hour < 10 || hour > 18 || isWeekend) { |
| 611 | `alert ( 'The office is closed.' ); // It is the weekend |
| 612 | `} |
| 613 | ^ OR || finds the first truthy value |
| 614 | a) The logic described above is somewhat classical |
| 615 | b) Now, let's bring in the 'extra' features of JS |
| 616 | c) The extended algorithm works as follows |
| 617 | d) Given multiple OR'ed values |
| 618 | `result = value1 || value2 || value3; |
| 619 | e) The OR operator does the following |
| 620 | `Evaluates operands from left to right |
| 621 | `For each operand, converts it to boolean |
| 622 | `If the result is true, stops and returns the original value of that operand |
| 623 | `If all operands have been evaluated (i.e. all were false), returns the last operand |
| 624 | f) A value is returned in its original form, without the conversion |
| 625 | `In other words, a chain of OR || returns the first truthy value or the last one if no truthy value is found |
| 626 | g) For instance |
| 627 | `alert( 1 || 0 ); // 1 is truthy |
| 628 | `alert( null || 1 ); // 1 is the first truthy value |
| 629 | `alert( null || 0 || 1 ); // 1 is the first truthy value |
| 630 | `alert( undefined || null || 0 ); // 0 all falsy, returns the last value |
| 631 | ^ OR || Finds the first truthy value (part 2) |
| 632 | a) This leads to some interesting usage compared to a 'pure, classical, boolean-only OR' |
| 633 | b) Getting the first truthy value from a list of variables or expressions |
| 634 | `For instance, we have firstName, lastName and nickName variables, all optional (i.e. can be undefined or have falsy values) |
| 635 | `Let's use OR || to choose the one that has the data and show it (or 'Anonymous' if nothing set) |
| 636 | ,let firstName = ""; |
| 637 | ,let lastName = ""; |
| 638 | ,let nickName = "SuperCoder"; |
| 639 | ,alert( firstName || lastName || nickName || 'Anonymous'); // SuperCoder |
| 640 | `If all variables were falsy, 'Anonymous' would show up |
| 641 | c) Short-circuit evaluation |
| 642 | `Another feature of OR || operator is the so-called 'short-circuit' evaluation |
| 643 | `It means that || processes its arguments until the first truthy value is reached, and then the value is returned immediately, without even touching the other argument |
| 644 | `The importance of this feature becomes obvious if an operand isn't just a value, but an expression with a side effect, such as a variable assignment of a function call |
| 645 | `In the example below, only the second message is printed |
| 646 | ,true || alert('not printed'); |
| 647 | ,false || alert('printed'); |
| 648 | `In the first line, the OR || operator stops the evaluation immediately upon seeing true, so the alert isn't run. |
| 649 | `Sometimes, people use this feature to execute commands only if the condition on the left part is falsy |
| 650 | ^ && (AND) |
| 651 | a) The ANS operator is represented with 2 ampersands && |
| 652 | `result = a && b; |
| 653 | b) In classical programming, AND returns true if both operands are truthy and false otherwise |
| 654 | c) alert (true && true); // true |
| 655 | `alert (true && false); // false |
| 656 | `alert (false && true); // false |
| 657 | `alert (false && false); // false |
| 658 | d) An example with if |
| 659 | `let hour = 12; |
| 660 | `let minute = 30; |
| 661 | `if (hour == 12 && minute == 30) { |
| 662 | `alert('The time is 12:30'); |
| 663 | `} |
| 664 | e) Just as with OR, any value is allowed as an operand of AND |
| 665 | `if (1 && 0) { // evaluated as true && false |
| 666 | `alert('Won't work, because the result is falsy'); |
| 667 | `} |
| 668 | ^ AND '&&' finds the first falsy value |
| 669 | a) Given multiple AND'ed values |
| 670 | `result = value1 && value2 && value3; |
| 671 | b) The AND && operator does the following |
| 672 | `Evaluates operands from left to right |
| 673 | `For each operand, converts it to a boolean. |
| 674 | ,If the result is false, stops and returns the original value of that operand |
| 675 | ,If all operands have been evaluated (i.e. all were truthy), returns the last operand |
| 676 | `In other words, AND returns the first falsy value or the last value if none were found |
| 677 | c) The rules above are similar to OR. |
| 678 | `The difference is that AND returns the first falsy value while OR returns the first truthy one. |
| 679 | d) Examples |
| 680 | `// if the first operand is truthy, AND returns the second operand |
| 681 | `alert(1 && 0); // 0 |
| 682 | `alert(1 && 5); // 5 |
| 683 | `// if the first operand is falsy, AND returns it |
| 684 | `// The second operand is ignored |
| 685 | `alert(null && 5); // null |
| 686 | `alert(0 && 'no matter what'); // 0 |
| 687 | e) We can also pass several values in a row. |
| 688 | `See how the first falsy one is returned |
| 689 | `alert(1 && 2 && null && 3); // null |
| 690 | f) When all values are truthy, the last value is returned |
| 691 | `alert(1 && 2 && 3); // 3 |
| 692 | ^ Precedence of AND && is higher than OR || |
| 693 | a) So the code a && b || c && d is essentially the same as if the && expressions were in parentheses |
| 694 | `(a && b) || (c && d) |
| 695 | ^ Don't replace 'if' with '||' or '&&' |
| 696 | a) Sometimes, people use the AND && operator as a 'shorter way to write if' |
| 697 | b) For instance |
| 698 | `let x = 1; |
| 699 | `(x > 0) && alert('Greater than zero'); |
| 700 | c) The action in the right part of && would execute only if the evaluation reaches it. |
| 701 | `That is, only if (x > 0) is true. |
| 702 | d) So we basically have an analogue for |
| 703 | `let x = 1; |
| 704 | `if (x > 0) alert('Greater than zero'); |
| 705 | e) Although, the variant with && appears shorter, 'if' is more obvious and tends to be a little bit more readable |
| 706 | f) So we recommend using every construct for its purpose |
| 707 | `use 'if' if we want 'if' and use '&&' if we want AND |
| 708 | * ! (NOT) |
| 709 | ^ |
| 710 | a) The boolean NOT operator is represented with an exclamation sign ! |
| 711 | b) The syntax is pretty simple |
| 712 | `result = !value; |
| 713 | c) The operator accepts a single argument and does the following |
| 714 | `Converts the operand to boolean type: true/false. |
| 715 | `Returns the inverse value |
| 716 | d) For instance |
| 717 | `alert(!true); // false |
| 718 | `alert(!0); // true |
| 719 | e) A double NOT !! is sometimes used for converting a value to a boolean type |
| 720 | `alert(!!'non-empty sting'); // true |
| 721 | `alert(!!null); // false |
| 722 | f) That is, the first NOT converts the value to boolean and returns the inverse, and the second NOT inverses it again. |
| 723 | `In the end, we have a plain value-to-boolean conversion |
| 724 | g) There's a little more verbose way to do the same thing -- a built-in boolean function |
| 725 | `alert( Boolean('non-empty string')); // true |
| 726 | `alert( Boolean(null)); // false |
| 727 | h) The precedence of NOT is the highest of all logical operators |
| 728 | `so it always executes first, before && or || |
| 729 | * Tasks (Logical operators) |
| 730 | ^ What is the code below going to output? |
| 731 | a) alert(null || 2 || undefined); // 2 (the first truthy value) |
| 732 | ^ What's the result of OR'ed alerts? |
| 733 | a) What will the code below output? |
| 734 | `alert( alert(1) || 2 || alert (3) ); // first 1, then 2 |
| 735 | b) The call to alert doesn't return a value |
| 736 | `In other words, it returns undefined |
| 737 | c) The first OR || evaluates its left operand alert(1) |
| 738 | `That shows the first message with 1 |
| 739 | d) The alert returns undefined |
| 740 | `so OR goes on to the second operand searching for a truthy value |
| 741 | e) The second operand 2 is truthy |
| 742 | `so the execution is halted |
| 743 | `2 is returned and then shown by the outer alert |
| 744 | f) There will be no 3, because the evaluation doesn't reach alert(3) |
| 745 | ^ What is this code going to show? |
| 746 | a) alert(1 && null && 2); // null, because it's the first falsy value from the list |
| 747 | ^ What is the result of AND'ed alerts? |
| 748 | a) alert( alert(1) && alert(2) ); // the answer 1, and then undefined |
| 749 | `The call to alert returns undefined |
| 750 | ,it just shows a message, so there's no meaningful return |
| 751 | `Because of that, && evaluates the left operand (outputs 1), and immediately stops, because undefined is a falsy value |
| 752 | `And && looks for a falsy value and returns it, so it's done |
| 753 | ^ The result of OR AND OR |
| 754 | a) What will the result be? |
| 755 | `alert(null || 2 && 3 || 4); // the answer 3 |
| 756 | b) The precedence of AND && if higher than ||, so it executes first |
| 757 | c) The result of 2 && 3 = 3, so the expression becomes |
| 758 | null || 3 || 4 |
| 759 | `Now the result is the first truthy value |
| 760 | ^ Check the range between |
| 761 | a) Write an 'if' condition to check that 'age' is between 14 and 90 inclusively |
| 762 | b) 'Inclusively' means that 'age' can reach the edges 14 or 90 |
| 763 | c) if (age >= 14 && age <= 90) |
| 764 | ^ Check the range outside |
| 765 | a) Write an 'if' condition to check that 'age' is NOT between 14 and 90 inclusively |
| 766 | b) Create two variants |
| 767 | `The first one using NOT '!' |
| 768 | `The second one without it |
| 769 | c) The first variant |
| 770 | `if (age < 14 || age > 90); |
| 771 | d) The second variant |
| 772 | `if (!(age >= 14 && age <= 90)); |
| 773 | ^ A question about 'if' |
| 774 | a) Which of these alerts are going to execute? |
| 775 | b) What will the results of the expressions be inside if(...)? |
| 776 | c) Tasks |
| 777 | `if (-1 || 0) alert('first'); |
| 778 | `if (-1 && 0) alert('second'); |
| 779 | `if (null || -1 && 1) alert('third'); |
| 780 | d) The answer: the first and the third will execute |
| 781 | e) Details |
| 782 | `// Runs |
| 783 | ,// The result of -1 || 0 = -1, truthy |
| 784 | `// Doesn't run |
| 785 | ,// -1 && 0 = 0, falsy |
| 786 | ,if (-1 && 0) alert('second'); |
| 787 | `// Executes |
| 788 | ,// Operator && has a higher precedence than || |
| 789 | ,// so -1 && 1 executes first, giving us the chain |
| 790 | ,// null || -1 && 1 -> null || 1 -> 1 |
| 791 | ,if (null || -1 && 1) alert('third'); |
| 792 | ^ Check the login |
| 793 | a) Write the code which asks for a login with prompt |
| 794 | b) If the visitor enters 'Admin', then prompt for a password, if the input is an empty line or Esc - show 'Canceled', if it's another string -- then show 'I don't know you' |
| 795 | c) The password is checked as follows |
| 796 | `If it equals 'TheMaster', then show 'Welcome' |
| 797 | `Another string -- show 'Wrong password' |
| 798 | `For an empty string or cancelled input, show 'Canceled' |
| 799 | d) The schema |
| 800 | `Begin -> Who's there? -> Cancel || Other || Admin |
| 801 | ,Admin -> Password -> (Cancel -> Canceled) || (Other -> Wrong password) || (TheMaster -> Welcome) |
| 802 | e) Please, use nested 'if' blocks |
| 803 | `Mind the overall readability of the code |
| 804 | f) Hint: passing an empty input to a prompt returns an empty string "". |
| 805 | `Pressing Esc during a prompt returns null |
| 806 | g) Decision |
| 807 | `let currentUserName = prompt("Who's there?", ''); |
| 808 | `if (currentUserName === 'Admin') { |
| 809 | `let pass = prompt('Password?', ''); |
| 810 | `if (pass === 'TheMaster') { |
| 811 | `alert('Welcome!'); |
| 812 | `} else if (pass === null || pass === '') { |
| 813 | `alert('Canceled'); |
| 814 | `} else { |
| 815 | `alert('Wrong password'); |
| 816 | `} |
| 817 | `} else if (currentUserName === null || currentUserName === '') { |
| 818 | `alert("Canceled"); |
| 819 | `} else { |
| 820 | `alert("I don't know"); |
| 821 | `} |
| 822 | h) Note the vertical indents inside the 'if' blocks. |
| 823 | `They're technically nore required, but make the code more readable |
| 824 | * Nullish coalescing operator '??' |
| 825 | ^ Introduction |
| 826 | a) This is a recent addition to the language |
| 827 | `Old browsers may need polyfills |
| 828 | b) The nullish coalescing operator is written as two question marks '??' |
| 829 | c) As it treats treats null and undefined similarly, we'll use a special term here, in this article |
| 830 | d) We'll say that an expression is 'defined' when it's neither null nor undefined |
| 831 | e) The result of a ?? b is |
| 832 | `if 'a' is defined, then 'a' |
| 833 | `if 'a' isn't defined, then 'b' |
| 834 | f) In other words, ?? returns the first argument if it's not null/undefined. |
| 835 | `Otherwise, the second one |
| 836 | g) The nullish coalescing operator isn't anything completely new |
| 837 | `It's just a nice syntax to get the first 'defined' value of the two |
| 838 | ^ Introduction (part 2) |
| 839 | a) We can rewrite result = a ?? b using the operators that we already know, like this |
| 840 | `result = (a !== null && a !== undefined) ? a : b; |
| 841 | b) Now it should be absolutely clear what ?? does |
| 842 | `Let's see where it helps |
| 843 | c) The common use case for ?? is to provide a default value for a potentially undefined variable |
| 844 | d) For example, here we show user if defined, otherwise Anonymous |
| 845 | `let user; |
| 846 | `alert(user ?? 'Anonymous'); // Anonymous (user not defined) |
| 847 | e) We can also use a sequence of ?? to select the first value from a list that isn't null/undefined |
| 848 | f) Let's say we have a user's data in variables firstName, lastName or nickName |
| 849 | `All of them may be not defined, if the user decided not to enter a value |
| 850 | g) We'd like to display the user name using one of these variables, or show 'Anonymous' if all of them aren't defined |
| 851 | `Let's use the ?? operator for that |
| 852 | ^ Introduction (part 3) |
| 853 | a) let firstName = null; |
| 854 | `let lastName = null; |
| 855 | `let nickName = 'Supercoder'; |
| 856 | `// Shows the first defined value |
| 857 | `alert(firstName ?? lastName ?? nickName ?? 'Anonymous'); // Supercoder |
| 858 | ^ Comparison with || |
| 859 | a) The OR || operator can be used in the same way as ?? |
| 860 | b) For example, in the code above we could replace ?? with || and still get the same result |
| 861 | `let firstName = null; |
| 862 | `let lastName = null; |
| 863 | `let nickName = 'Supercoder'; |
| 864 | `// Shows the first truthy value |
| 865 | `alert(firstName || lastName || nickName || 'Anonymous'); // Supercoder |
| 866 | c) Historically, the OR || operator was there first |
| 867 | `It exists since the beginning of JS |
| 868 | `So developers were using it for such purposes for a long time |
| 869 | d) On the other hand, the nullish coalescing operator ?? was added to JS only recently |
| 870 | `And the reason for that was that people weren't quite happy with || |
| 871 | e) The important difference between them is that |
| 872 | `|| returns the first truthy value |
| 873 | `?? returns the first defined value |
| 874 | f) In other words, || doesn't distinguish between false, 0, an empty string "" and null/undefined |
| 875 | `They're all the same -- falsy values |
| 876 | `If any of these is the first argument of ||, then we'll get the second argument as the result |
| 877 | g) In practice though, we may want to use default value only when the variable is null/undefined |
| 878 | `That is, when the value is really unknown/not set |
| 879 | ^ Comparison with || (part 2) |
| 880 | a) For example, consider this |
| 881 | `let height = 0; |
| 882 | `alert(height || 100); // 100 |
| 883 | `alert(height ?? 100); // 0 |
| 884 | b) The height || 100 checks height for being a falsy value, and it's 0, falsy indeed |
| 885 | `So the result of || is the second argument, 100 |
| 886 | c) The height ?? 100 checks height for being null/undefined, and it's not |
| 887 | `So the result is height 'as is', that is 0 |
| 888 | d) In practise, the zero height is often a valid value, that shouldn't be replaced with the default |
| 889 | `So ?? does just the right thing |
| 890 | * Precedence (??) |
| 891 | ^ Introduction |
| 892 | a) The precedence of the ?? operator is about the same as ||, just a bit lower |
| 893 | `5 ?? against 6 || |
| 894 | b) That means that, just like ||, the nullish coalescing operator ?? is evaluated before = and ?, but after most other operations, such as +, * |
| 895 | c) So if we'd like to choose a value with ?? in an expression with other operators, consider adding parentheses |
| 896 | `let height = null; |
| 897 | `let width = null; |
| 898 | `// important: use parentheses |
| 899 | `let area = (height ?? 100) * (width ?? 50); |
| 900 | `alert(area); // 5000 |
| 901 | d) Otherwise, if we omit parentheses, then as * has the higher precedence than ??, it would execute first, leading to incorrect results |
| 902 | `// Without parentheses |
| 903 | `let area = height ?? 100 * width ?? 50; |
| 904 | `// ... works the same as this (probably not what we want): |
| 905 | `let area = height ?? (100 * width) ?? 50; |
| 906 | * Using ?? with && or || |
| 907 | ^ |
| 908 | a) Due to safety reasons, JS forbids using ?? together with && and || operators, unless the precedence is explicitly specified with parentheses |
| 909 | b) The code below triggers a syntax error |
| 910 | `let x = 1 && 2 ?? 3; // Syntax error |
| 911 | c) The limitation is surely debatable, it was added to the language specification with the purpose to avoid programming mistakes, |
| 912 | when people start to switch from || to ?? |
| 913 | d) Use explicit parentheses to work around it |
| 914 | `let x = (1 && 2) ?? 3; // works |
| 915 | `alert(x); // 2 |
| 916 | * Summary (??) |
| 917 | ^ |
| 918 | a) The nullish coalescing operator ?? provides a short way to choose the first 'defined value from a list' |
| 919 | b) It's used to assign default values to variables |
| 920 | `// Set height = 100, if height is null or undefined |
| 921 | `height = height ?? 100; |
| 922 | c) The operator ?? has a very low precedence, only a bit higher than ? and = |
| 923 | `So consider adding parentheses when using it in an expression |
| 924 | d) It's forbidden to use it with || or && without explicit parentheses |
| 925 | * Loops: while and for |
| 926 | ^ Introduction |
| 927 | a) We often need to repeat actions |
| 928 | b) For example, outputting goods from a list one after another or just running the same code for each number from 1 to 10 |
| 929 | c) Loops are a way to repeat the same code multiple times |
| 930 | ^ The 'while' loop |
| 931 | a) while (condition) { |
| 932 | `// code |
| 933 | `// so-called 'loop body' |
| 934 | `} |
| 935 | b) While the condition is truthy, the code from the loop body is executed |
| 936 | d) For instance, the loop below outputs 'i' while i < 3 |
| 937 | `let i = 0; |
| 938 | `while (i < 3) { // shows 0, then 1, then 2 |
| 939 | `alert(i); |
| 940 | `i++;; |
| 941 | `} |
| 942 | e) A single execution of the loop body is called an iteration. |
| 943 | `The loop in the example above makes three iterations |
| 944 | f) If i++ was missing from the example above, the loop would repeat (in theory) forever. |
| 945 | g) In practise, the browser provides ways to stop such loops |
| 946 | `And in server-side JS, we can kill the process |
| 947 | ^ The 'while' loop (part 2) |
| 948 | a) Any expression or variable can be a loop condition, not just comparisons |
| 949 | `The condition is evaluated and converted to a boolean by while |
| 950 | b) For instance, a shorter way to write while (i != 0) is while (i) |
| 951 | `let i = 3; |
| 952 | `while (i) { // when i becomes 0, the condition becomes falsy, and the loop stops |
| 953 | `alert (i); |
| 954 | `i--; |
| 955 | `} |
| 956 | ^ Curly braces are not required for a single-line body |
| 957 | a) If the loop body has a single statement, we can omit the curly braces {...} |
| 958 | `let i = 3; |
| 959 | `while (i) alert(i--); |
| 960 | * The 'do...while' loop |
| 961 | ^ |
| 962 | a) The condition check can be moved below the loop body using the do...while syntax |
| 963 | `do { |
| 964 | `// loop body |
| 965 | `} while (condition) |
| 966 | b) The loop will first execute the body, then check the condition, and, while it's truthy, execute it again and again |
| 967 | c) For example |
| 968 | `let i = 0; |
| 969 | `do { |
| 970 | `alert(i); |
| 971 | `i++; |
| 972 | `} while (i < 3); |
| 973 | d) This form of syntax should only be used when you want the body of the loop to execute at least once regardless of the condition being truthy |
| 974 | - Usually, the other form is preferred: |
| 975 | `while (...) {...} |
| 976 | * The 'for' loop |
| 977 | ^ |
| 978 | a) The 'for' loop is more complex, but it's also the most commonly used loop |
| 979 | - It looks like this |
| 980 | `for (begin; condition; step) { |
| 981 | `// loop body |
| 982 | `} |
| 983 | b) Let's learn the meaning of these parts by example |
| 984 | - The loop below runs alert(i) for i from 0 up to (but not including) 3 |
| 985 | `for (let i = 0; i < 3; i++) { // shows 0, then 1, then 2 |
| 986 | `alert(i); |
| 987 | `} |
| 988 | c) Let's examine the 'for' statement part-by-part |
| 989 | - part |
| 990 | `begin |
| 991 | ,let i = 0; // Executes once upon entering the loop |
| 992 | `condition |
| 993 | ,i < 3; // Checked before every loop iteration. If false, the loop stops |
| 994 | `body |
| 995 | ,alert(i); // Runs again and again while the condition is truthy |
| 996 | `step |
| 997 | ,i++; // Executes after the body on each iteration |
| 998 | d) The general loop algorithm works like this |
| 999 | - Run begin |
| 1000 | `-> (if condition -> run body and run step) |
| 1001 | `-> (if condition -> run body and run step) |
| 1002 | `-> (if condition -> run body and run step) |
| 1003 | `-> ... |
| 1004 | e) That is, 'begin' executes once, and then it iterates |
| 1005 | - after each 'condition' test, 'body' and 'step' are executed |
| 1006 | f) If you're a new to loops, it could help to go back to the example |
| 1007 | and reproduce how it runs step-by-step on a piece of paper |
| 1008 | ^ The 'for' loop (part 2) |
| 1009 | a) Here's exactly what happens in our case |
| 1010 | - // for (let i = 0; i < 3; i++) alert (i) |
| 1011 | - // run begin |
| 1012 | `let i = 0; |
| 1013 | - // if condition -> run body and run step |
| 1014 | `if (i < 3) { alert(i); i++ } |
| 1015 | - // if condition -> run body and run step |
| 1016 | `if (i < 3) { alert(i); i++ } |
| 1017 | - // if condition -> run body and run step |
| 1018 | `if (i < 3) { alert(i); i++ } |
| 1019 | - // finish, because now i == 3 |
| 1020 | ^ Inline variable declaration |
| 1021 | a) Here, the 'counter' variable i is declared right in the loop |
| 1022 | - This is called an 'inline' variable declaration |
| 1023 | - Such variables are visible only inside the loop |
| 1024 | b) for (let i = 0; i < 3; i++) { |
| 1025 | - alert(i); // 0, 1, 2 |
| 1026 | - } |
| 1027 | - alert(i); // error, no such variable |
| 1028 | c) Instead of defining a variable, we could use an existing one |
| 1029 | - let i = 0; |
| 1030 | - for (i = 0; i < 3; i++) { |
| 1031 | - alert(i); |
| 1032 | - } |
| 1033 | - alert(i); // 3, visible, because declared outside of the loop |
| 1034 | ^ Skipping parts |
| 1035 | a) Any part of 'for' can be skipped |
| 1036 | b) For example, we can omit begin if we don't need to do anything at the loop start |
| 1037 | c) Like here |
| 1038 | - let i = 0; // we have i already declared and assigned |
| 1039 | - for (; i < 3; i++) { // no need 'for' begin |
| 1040 | - alert(i); // 0, 1, 2 |
| 1041 | - } |
| 1042 | d) We can also remove the 'step' part |
| 1043 | - let i = 0; |
| 1044 | - for (; i < 3;) { |
| 1045 | - alert(i++); |
| 1046 | - } |
| 1047 | e) This makes the loop identical to while (i < 3) |
| 1048 | f) We can actually remove everything, creating an infinite loop |
| 1049 | - for (;;) { |
| 1050 | - // repeats without limits |
| 1051 | - } |
| 1052 | g) Please note that the two 'for' semicolons ';' must be present |
| 1053 | - Otherwise, there would be a syntax error |
| 1054 | ^ Breaking the loop |
| 1055 | a) Normally, a loop exits when its condition becomes falsy |
| 1056 | b) But we can force exits at any time using the special 'break' directive |
| 1057 | c) For example, the loop below asks the user for a series of numbers, 'breaking' when no number is entered |
| 1058 | - let sum = 0; |
| 1059 | - while (true) { |
| 1060 | - let value = +prompt('Enter a number', ""); |
| 1061 | - if (!value) break; // (*) |
| 1062 | - sum += value; |
| 1063 | - } |
| 1064 | - alert('Sum: ' + sum); |
| 1065 | d) The 'break' directive is activated at the line (*) if the user enters an empty line or cancels the input. |
| 1066 | e) It stops the loop immediately, passing control to the first line after the loop. |
| 1067 | - Namely, 'alert' |
| 1068 | e) The combination 'infinite loop + 'break' as needed' is great for situations when a loop's condition must be checked not in the beginning or end of the loop, but in the middle or even in several places of its body |
| 1069 | ^ Continue to the next iteration |
| 1070 | a) The 'continue' directive is a 'lighter version' of 'break' |
| 1071 | b) It doesn't stop the whole loop |
| 1072 | c) Instead, it stops the current iteration and forces the loop to start a new one (if the condition allows) |
| 1073 | d) We can use it if we're done with the current iteration and would like to move on to the next one |
| 1074 | e) The loop below uses 'continue' to output only odd values |
| 1075 | - for (let i = 0; i < 10; i++) { |
| 1076 | - // if true, skip the remaining part of the body |
| 1077 | - if (i % 2 == 0) continue; |
| 1078 | - alert(i); // 1, then 3, 5, 7, 9 |
| 1079 | - } |
| 1080 | f) For even values of 'i', the 'continue' directive stops executing the body and passes control to the next iteration of 'for' (with the next number) |
| 1081 | g) So the alert is only called for odd values |
| 1082 | ^ The 'continue' directive helps decrease nesting |
| 1083 | a) A loop that shows odd values could look like this |
| 1084 | - for (let i = 0; i < 10; i++) { |
| 1085 | - if (i % 2) { |
| 1086 | - alert(i); |
| 1087 | -} |
| 1088 | -} |
| 1089 | b) From a technical point of view, this is identical to the example above |
| 1090 | c) Surely, we can just wrap the code in an 'if' block instead of using 'continue' |
| 1091 | d) But as a side-effect, this created one more level of nesting (the alert call inside the curly braces) |
| 1092 | e) If the code inside of 'if' no longer than a few lines, that may decrease the overall readability |
| 1093 | ^ No 'break/continue' to the right side of '?' |
| 1094 | a) Please note that syntax constructs that are not expressions can't be used with the ternary operator '?' |
| 1095 | b) In particular, directives such an 'break/continue' aren't allowed there |
| 1096 | c) For example, if we take this code |
| 1097 | - if (i > 5) { |
| 1098 | - alert(i); |
| 1099 | - } else { |
| 1100 | - continue; |
| 1101 | - } |
| 1102 | d) And rewrite it using a question mark '?' |
| 1103 | - (i > 5) ? alert(i) : continue; // continue isn't allowed here |
| 1104 | e) It stops working |
| 1105 | - there's a syntax error |
| 1106 | f) This is just another reason not to use the question mark operator ? instead of if |
| 1107 | * Labels for break/continue |
| 1108 | ^ Part 1 |
| 1109 | a) Sometimes we need to break out from multiple nested loops at once |
| 1110 | b) For example, in the code below we loop over 'i' and 'j', prompting for the coordinates (i, j) from (0, 0) to (2, 2) |
| 1111 | - for (let i = 0; i < 3; i++) { |
| 1112 | - for (let j = 0; j < 3; j++) { |
| 1113 | - let input = prompt(`Value at coords (${1}, ${j}`, ""); |
| 1114 | - // what if we want to exit from here to Done (below)? |
| 1115 | - } |
| 1116 | - } |
| 1117 | - alert('Done'); |
| 1118 | c) We need a way to stop the process if the user cancels the input |
| 1119 | d) The ordinary 'break' after 'input' would only break the inner loop |
| 1120 | e) That's not sufficient - labels, come to the rescue |
| 1121 | f) A label is an identifier with a colon before a loop |
| 1122 | - labelName: for (...) { |
| 1123 | - ... |
| 1124 | - } |
| 1125 | ^ Labels for break/continue (Part 2) |
| 1126 | a) The 'break <labelName> statement in the loop below breaks out to the label |
| 1127 | - outer: for (let i = 0; i < 3; i++) { |
| 1128 | - for (let j = 0; j < 3; J++) { |
| 1129 | - let input = prompt(`Value at coords (${i}, ${j})`, ""); |
| 1130 | - // if an empty string or canceled, then break out of both loops |
| 1131 | - if (!input) break outer; // (*) |
| 1132 | - // do something with the value |
| 1133 | - } |
| 1134 | - } |
| 1135 | - alert('Done'); |
| 1136 | b) In the code above, break outer looks upwards for the label named 'outer' and breaks out of that loop |
| 1137 | c) So the control goes straight from (*) to alert('Done') |
| 1138 | d) We can also move the label onto a separate line |
| 1139 | - outer: |
| 1140 | - for (let i = 0; i < 3; i++) {...} |
| 1141 | e) The 'continue' directive can also be used with a label. |
| 1142 | f) In this case, code execution jumps to the next iteration of the labeled loop. |
| 1143 | ^ Labels do not allow to 'jump' anywhere |
| 1144 | a) Labels don't allow us to jump into an arbitrary place in the code |
| 1145 | b) For example, it's impossible to do this |
| 1146 | - break label; // jump to the label below (doesn't work) |
| 1147 | - label: for (...) |
| 1148 | c) A break directive must be inside a code block |
| 1149 | d) Technically, any labelled code block will do, e.g.: |
| 1150 | - label: { |
| 1151 | - // ... |
| 1152 | - break label; // works |
| 1153 | - // ... |
| 1154 | - } |
| 1155 | e) Although, 99,9% of the time 'break' is used inside loops, as we've seen in the examples above |
| 1156 | f) A 'continue' is only possible from inside a loop |
| 1157 | ^ Summary |
| 1158 | a) We covered 3 types of loops |
| 1159 | - while -- The condition is checked before each iteration |
| 1160 | - do..while -- The condition is checked after each iteration |
| 1161 | - for (;;) -- The condition is checked before each iteration, additional settings available |
| 1162 | b) To make an 'infinite' loop, usually the 'while(true)' construct is used. |
| 1163 | - Such a loop, just like any other, can be stopped with the 'brea' directive |
| 1164 | c) If we don't want to do anything in the current iteration and would like to forward to the next one, we can use the 'continue' directive |
| 1165 | d) 'break/continue' support labels before the loop |
| 1166 | - A label is the only way for 'break/continue' to escape a nested loop to go to an outer one. |
| 1167 | * Tasks (Loops) |
| 1168 | ^ Last loop value |
| 1169 | a) What is the last value alerted by this code? Why? |
| 1170 | - let i = 3; |
| 1171 | - while (i) { |
| 1172 | - alert(i--); |
| 1173 | - } |
| 1174 | b) Answer |
| 1175 | - Every loop iteration decreases 'i' by 1 |
| 1176 | - The check while(i) stops the loop when i = 0 |
| 1177 | - Hence, the steps of the loop form the following sequence ('loop unrolled') |
| 1178 | c) Answer (continue) |
| 1179 | - let i = 3; |
| 1180 | - alert(i--); // shows 3, decreases i to 2 |
| 1181 | - alert(i--); // shows 2, decreases i to 1 |
| 1182 | - alert(i--); // shows 1, decreases i to 0 |
| 1183 | - // done, while(i) check stops the loop |
| 1184 | ^ Which values does the while loop show? |
| 1185 | a) For every loop iteration, write down which value it outputs and then compare it with the solution |
| 1186 | b) Both loops 'alert' the same values, or not? |
| 1187 | - The prefix form ++1 |
| 1188 | `let i = 0; |
| 1189 | `while (++i < 5) alert (i); |
| 1190 | - The postfix form 1++ |
| 1191 | `let i = 0; |
| 1192 | `while (i++ < 5) alert (i); |
| 1193 | c) Answer. The task demonstrates how postfix/prefix forms can lead to different results when used in comparisons |
| 1194 | - From 1 to 4 |
| 1195 | `The first value is i = 1, because ++i first increments i and then returns the new value |
| 1196 | `So the first comparison is 1 < 5 and then 'alert' shows '1' |
| 1197 | `Then follow 2, 3, 4 -- the values show up one after another |
| 1198 | `The comparison always uses the incremented value, because ++ is before the variable |
| 1199 | `Finally, i = 4 is incremented to 5, the comparison while(5 < 5) fails, and the loop stops |
| 1200 | `So 5 is not shown |
| 1201 | - From 1 to 5 |
| 1202 | `The first value is again i = 1. |
| 1203 | `The postfix form of i++ increments 'i' and then returns the old value, so the comparison i++ < 5 will use i = 0 (contrary to i++ < 5) |
| 1204 | `But the alert calls is separate |
| 1205 | `It's another statement which executes after the increment and the comparison |
| 1206 | `So it gets the current i = 1 |
| 1207 | `Then follow 2, 3, 4 |
| 1208 | `Let's stop on i = 4 |
| 1209 | `The prefix form ++i would increment it and use 5 in the comparison |
| 1210 | `But here we have the postfix form i++ |
| 1211 | `So it increments 'i' to 5, but returns the old value |
| 1212 | `Hence the comparison is actually while(4 < 5) - true, and the control goes on to alert |
| 1213 | `The value i = 5 is the last one, because on the next step while(5 < 5) is false |
| 1214 | ^ Which values get shown by the 'for' loop |
| 1215 | a) For each loop write down which values it is going to show. Then compare with the answer |
| 1216 | b) Both loops alert same values or not? |
| 1217 | - The postfix form |
| 1218 | `for (let i = 0; i < 5; i++) alert(i); |
| 1219 | - The prefix form |
| 1220 | `for (let i = 0; i < 5; ++i) alert(i); |
| 1221 | c) The answer: from 0 to 4 in both cases |
| 1222 | - That can be easily deducted from the algorithm of 'for' |
| 1223 | `Execute once i = 0 before every thing (begin) |
| 1224 | `Check the condition i < 5 |
| 1225 | `If 'true' -- executes the loop body alert(i), and then i++ |
| 1226 | - The increment i++ is separated from the condition i < 5 |
| 1227 | `That's just another statement |
| 1228 | - The value returned by the increment is not used here, so there's no difference between ++i and i++ |
Комментарии