/ 

Ref/control flow!

How to Code: The Fundamentals, pt 3

URL copied to clipboard
By AstroMacGuffin dated  last updated 
![digital-identitySmall.jpg](/static/img/mm/cyberspace/digital-identitySmall.jpg) In part 2 we dealt with `async`/`await`, objects and classes. In part 3, we're getting into Arrays and a little further into objects, plus we're taking another bite of control flow. These unrelated topics are closely linked in actual use. In this lesson, we'll cover: - arrays - how to find your way around objects and arrays - data type methods & built-in objects - comparison operators - `for` loops and the `Array.forEach` method - the Increment (`++`) and Decrement (`--`) operators - `while` loops


### Data Type Methods & Built-in Objects On a certain level, everything in JavaScript is an object. Your string variables have object methods, and even a hard-coded string has those same methods. The same is true of numbers, Arrays, and, of course, all the built-in objects you can access just by virtue of the fact that you're writing JavaScript code. For example, Arrays have the `.join()` method which turns the Array into a string; and strings have the `.split()` method which turns the string into an Array. And complementing those methods attached to the individual String, Number, and Array "objects" in your code, there are the Standard Built-in Objects. These objects' classes have methods that are sometimes uniquely useful, like `Array.isArray()` or `Object.keys()`. Of course MDN has a [full list](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects) of all the built-ins, but it's probably more useful if I hand-pick a few: [Object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object), [Number](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number), [Math](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math), [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date), [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String), [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp), [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array), [JSON](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON), and [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) are the ones I use the most. ### Arrays If a variable is a box, then an Array is a box full of boxes. The internal boxes are numbered, starting with #0 for the first box. Those boxes can also be subdivided into boxes, as many layers deep as you need. The following code sample contains a smattering of things you need to know about Arrays: ```js let arr = []; // create an empty array arr[0] = 'Arrays'; // set the 1st element arr.push('rule'); // add an element at the end console.log( arr[1] ); // output the 2nd element if (arr.indexOf('rule') > -1) { /* do something if 'rule' appears in array */ } let str = arr.join(' '); // make string with spaces between elements ``` #### Finding Your Way Around Arrays Arrays never use dot notation -- they only use square brackets. Since you can have arrays within arrays, and objects within arrays, let's go into some example cases. ```js const arrayOfObjects = [ // element 0: an object with info for the 1st Doctor { doctor: '1st', actor: 'Hartnell' }, // element 1: an object with info for the 9th Doctor { doctor: '9th', actor: 'Eccleston'} ]; console.log( arrayOfObjects[0].actor ); // outputs 'Hartnell' ``` Array element position numbers start at 0 and increment by 1 from there. So, `arrayOfObjects[0]` addresses the first element of `arrayOfObjects`. The first element of `arrayOfObjects` is an object, so we can address one of its fields by adding `.actor`. Next, let's look at an array of arrays, aka a "multi-dimensional array". ```js const arrayOfArrays = [ // element 0: an array of dark colors ['navy blue', 'forest green', 'dark grey', 'black'], // element 1: an array of light colors ['sky blue', 'bright green', 'light grey', 'white'] ]; console.log( arrayOfArrays[1][3] ); // outputs 'white' ``` Arrays can contain arrays that hold arrays *full* of arrays, on and on, with more and more dimensions of data complexity. Later in this lesson, you'll see how to step through arrays using two types of loops designed specifically for that job. There are a lot more than two, though! ![700422main_ESA_Fomalhaut_Exoplanet_Still.png](/static/img/mm/space/700422main_ESA_Fomalhaut_Exoplanet_Still.png) #### Array Methods There are many other methods automatically attached to every Array object you create in your code. MDN has a [comprehensive guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array), of course. To get you started, here are a few key Array methods. ##### `.indexOf()` and Other Search Methods Assume you have an Array called `arr` and you want to know if something is in that Array, or even want to know *where* it is in that Array. The code `arr.indexOf(thing)` returns the index of `thing` in Array `arr`. When you're using `.indexOf` simply to test whether the `thing` is in the Array, remember, Arrays start at index 0, meaning a 0 is a hit. So in a conditional like that, think like this: - **-1** is false (the `thing` is **not** in the Array), - **greater than -1** is true (the `thing` **is** in the Array). ```js let arr = ['Arrays', 'rule']; if ( arr.indexOf('rule') > -1 ) { // index greater than -1 = hit } ``` There's also `.find()` which lets you specify a testing function. `.find()` returns the first Array entry that makes your testing function `return true`. ```js let arr = ['Arrays', 'rule']; let match = arr.find( /* begin testing function */ (item) => { // testing function code return item.startsWith('Array'); } ); console.log( match ); // outputs "Arrays" ``` The Array method `.lastIndexOf()` is just like `.indexOf()` but it starts its search at the end of the Array and steps backwards until it finds a match. It returns -1 if no match was found, or if a match was found it returns the index of the found match. ##### `.push()` and Other Insertion Methods The `.push()` method inserts one or more new elements at the end of the Array. ```js const arr = ['Arrays', 'rule']; arr.push('and'); arr.push('objects', 'do', 'too'); // add multiple console.log( arr.length ); // outputs "6" ``` The `.unshift()` method adds one or more new elements at the beginning of the Array. ```js const arr = ['Eccleston', 'Tennant', 'Smith', 'Capaldi', 'Whittaker']; arr.unshift( 'Hartnell', 'Troughton', 'Pertwee', 'Baker', 'Davison', 'Baker', 'McCoy', 'McGann' ); console.log( arr ); /* output: [ 'Hartnell', 'Troughton', 'Pertwee', 'Baker', 'Davison', 'Baker', 'McCoy', 'McGann', 'Eccleston', 'Tennant', 'Smith', 'Capaldi', 'Whittaker' ] */ ``` Finally the `.splice()` method. This method is versatile: it deletes, it inserts, it'll chop off half the array or more... all depending on how you use it. For insertion at some arbitrary point in the Array, you need the index for the new entry (or entries). Anything currently at that position or later, will be bumped. Let's say you have the index in the variable `index`... you would do: ```js const arr = ['apple', 'banana', 'grape']; // let's suppose a variable index === 2 arr.splice(index, 0, 'canteloupe', 'dragonfruit'); console.log( arr ); // outputs: // [ 'apple', 'banana', 'canteloupe', 'dragonfruit', 'grape' ] ``` That second argument to `.splice()`, which is set to 0 above, is the number of elements you want to delete at that position. So you can replace, insert, do a mass delete and an insert at the same time, etc. You can also do deletions *without insertions* using `.splice()`, because the list of new entries is an optional parameter. And, you can chop off every element after `index` using `.splice()`, by leaving off the second parameter. ##### `.join()` and Other Misc Methods The `.join()` method turns an Array into a string, using a string as a linker between elements. Example: ```js const arr = ['Arrays', 'rule', 'and', 'so', 'do', 'objects']; console.log( arr.join(' ') ); // outputs "Arrays rule and so do objects" ``` The `Array.isArray()` static class method is how we deal with the fact that the following code outputs the string, "object": ```js let x = [1, 2, 3, 4, 5]; console.log( typeof x ); // outputs: "object" ``` (`typeof` will be covered later this lesson; for now just understand it outputs a string, equal to the category of whatever's to the right of the word `typeof`.) So we can't use `typeof` to find out if something is an Array. We have to use `Array.isArray()`. It's not `theVariable.isArray()`, it's `Array.isArray(theVariable)`, because this is a static class method rather than an object method. The `.map()` method creates a new Array whose elements are generated by a callback function. You provide the callback function, which is run once per element in the Array. The callback function automatically receives inputs so long as you set the function signature to receive them. The usual signature is either `(item)` which gives you the element (each one, one iteration at a time), or `(item, index)` which gives you the element plus its index in the Array. ```js const arr = [1, 2, 3, 4, 5]; const a = arr.map( (item) => { return item*5; }); console.log( a ); // output: [ 5, 10, 15, 20, 25 ] ``` The `.filter()` method copies a portion of an Array. You provide a function as the first (and usually only) argument to `.filter()`. This function gets run once for every element in the Array. The function receives input automatically, you just have to set your signature to handle those inputs. The two most commonly used signatures are `(item, index)` where `item` is the element and `index` is its index; or `(item)` -- same as before, minus the index. ```js const arr = [1, 2, 3, 4, 5]; const a = arr.filter( (item, index) => { if (index > 0 && index < 4) return true; else return false; }); console.log( a ); a[0] = ' Swiss'; console.log( arr ); ``` Interestingly, the above script didn't perform the same exact way across JavaScript implementations. For one thing, the documentation for `.filter()` says the copy remains linked to the source Array, and therefore changing an element in one Array, should change the other; but the two Arrays were independent in both Node.js and Opera Browser (which is a fork of Chrome, under the hood). Also, my browser assigned `a[0]` the value of `"Swiss"` before outputting the content of `a`; that is, the `console.log()` method was somehow delayed, but only in the browser. I have no explanation for this quirk and my only advice is, test often. #### Moving On Arrays do a lot more than what I've demonstrated here (we'll cover one more Array method later this lesson). Always remember you can learn more reading the [MDN reference for Arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array), just as soon as you get comfortable reading its more technical format. ![640px-Wide-field_view_of_the_Summer_Triangle.jpg](/static/img/mm/space/640px-Wide-field_view_of_the_Summer_Triangle.jpg) ### How to Find your Way around Objects Just like with Arrays, it's all fantastic that an object can hold multiple values, but that does nothing for you if you don't know how to access the data inside. #### Objects & Sub-Objects Let's say you have an object like this: ```js const fruitColor = { banana: "yellow", apple: "red", pear: "green", } ``` I think we all know by now that this will output `red`: ```js console.log( fruitColor.apple ); ``` You can continue chaining dots and field names so long as necessary to address nested objects: ```js const fruitColor = { banana: "yellow", apple: { fuji: "red", grannySmith: "green" }, pear: "green", } ``` To output `red` from the above data, we now: ```js console.log( fruitColor.apple.fuji ); ``` #### Finding Object Properties Using Variables But what if the choice of fruit was unknown until runtime? What if you needed to use a variable to select into the `fruitColor` object, to identify which property you want? There is an alternate syntax for that: ```js let whichFruit = 'banana'; console.log( fruitColor[whichFruit] ); ``` Since `apple` was broken down to `fuji` and `grannySmith` in a sub-object, dynamic addressing gets a little more involved. If we want to output `red` from that data: ```js let whichFruit = 'apple'; let whichType = 'fuji'; if (whichType) console.log( fruitColor[whichFruit][whichType] ); else console.log( fruitColor[whichFruit] ); ``` You can mix and match dot notation vs square brackets as needed. For example, these are both the same thing: ```js console.log( fruitColor.apple['fuji'] ); // red console.log( fruitColor['apple'].fuji ); // red ``` But this doesn't work: ```js console.log( fruitColor["apple.fuji"] ); // undefined ``` ***By the way,*** you might notice I left off the curly braces on the `if`/`else` above. Any control flow feature that involves curly braces (so, almost all of them) can be done without the curly braces -- in which case, only one statement will happen (or not happen) as a result of that control flow feature. This is illustrated in the example code above: both the `if` and the `else` each have only one line indented under them. (That indentation is only to remind the programmer about the *scope* of each block (or line) of code -- indentation isn't a flow control feature in JavaScript.) #### A Peek Ahead Finally, looping through objects. We're getting ahead a bit, but we'll come back to it later this lesson. You use the `Object.keys()` method to get an Array of the keys, and then you loop through that Array, using the values you find along the way to select into the object. Like this: ```js const obj = { ball: "round", seeSaw: "flat", truck: "complex" }; const keys = Object.keys( obj ); keys.forEach( (item) => { console.log( obj[item] ); }); /* output: round flat complex */ ``` ### Comparison Operators & Other Related Operators So far we've only discussed one of the "comparison operators" -- that being `===` the Strict Equality operator. But there are many operators you can use to make a conditional: <table> <tr><th>Operator</th><th>Effect</th><th>Example</th></tr> <tr><td style="padding: 4px 20px 0 0"><code>===</code></td><td style="padding: 4px 20px 0 0">returns true if values are equal and of equal type</td> <td style="padding: 4px 0 0 0"><code>if (x === y)</code></td></tr> <tr><td style="padding: 4px 20px 0 0"><code>==</code></td><td style="padding: 4px 20px 0 0">returns true if values are equal after type conversion</td> <td style="padding: 4px 0 0 0"><code>if (x == y)</code></td></tr> <tr><td style="padding: 4px 20px 0 0"><code><</code></td><td style="padding: 4px 20px 0 0">returns true if number to left is smaller than number to right;<br/>or if string to left comes alphabetically earlier than the string on the right</td> <td style="padding: 4px 0 0 0"><code>if (x < y)</code></td></tr> <tr><td style="padding: 4px 20px 0 0"><code>></code></td><td style="padding: 4px 20px 0 0">returns true if number to left is larger than number to right;<br/>or if string to left comes alphabetically after the string on the right</td> <td style="padding: 4px 0 0 0"><code>if (x > y)</code></td></tr> <tr><td style="padding: 4px 20px 0 0"><code><=</code></td><td style="padding: 4px 20px 0 0">returns true if value to left of operator is less than or equal to the value on the right</td> <td style="padding: 4px 0 0 0"><code>if (x <= y)</code></td></tr> <tr><td style="padding: 4px 20px 0 0"><code>>=</code></td><td style="padding: 4px 20px 0 0">returns true if value to the left is greater than or equal to the value on the right</td> <td style="padding: 4px 0 0 0"><code>if (x >= y)</code></td></tr> <tr><td style="padding: 4px 20px 0 0"><code>!==</code></td><td style="padding: 4px 20px 0 0">returns true if the two values are not equal or don't have equal type</td> <td style="padding: 4px 0 0 0"><code>if (x !== y)</code></td></tr> <tr><td style="padding: 4px 20px 0 0"><code>!=</code></td><td style="padding: 4px 20px 0 0">returns true if the two values are not equal after type conversion</td> <td style="padding: 4px 0 0 0"><code>if (x != y)</code></td></tr> <tr><td style="padding: 4px 20px 0 0"><code>in</code></td><td style="padding: 4px 20px 0 0">returns true if the string on the left of the operator is a key in the object to the right of the operator</td> <td style="padding: 4px 0 0 0"><code>if ("message" in error)</code></td></tr> <tr><td style="padding: 4px 20px 0 0"><code>typeof</code></td><td style="padding: 4px 20px 0 0">returns a string describing the type of the variable after the operator</td> <td style="padding: 4px 0 0 0"><code>if (typeof str === 'string')</code></td></tr> <tr><td style="padding: 4px 20px 0 0"><code>instanceof</code></td><td style="padding: 4px 20px 0 0">returns true if the class reference on the right, is anywhere in the ancestry of the object on the left</td> <td style="padding: 4px 0 0 0"><code>if (obj instanceof Object)</code></td></tr> </table> ![The theme today is "space pics I have ready at hand"](/static/img/mm/space/286486215_1888a8154a_o.jpg) ### `for` loops and the `Array.forEach` Method I'm going to be honest with you, dear students. I don't know a single one of the newfangled `for` loops, just what I call the "traditional `for` loop". It looks like this: ```js for (let i = 0; i < something.length; i++) { // looped code } ``` As you can see in the parentheses above, the `for` statement has three arguments separated by semicolons: - The first one happens when the loop is about to begin - The second one is a conditional that determines whether the loop happens, or happens again - The third one happens after each run of the loop So in the example above: 1. A variable called `i` is declared and defined as `0`. 2. Then `i` is compared to something called `something.length`. Arrays have a `.length` property that contains the number of entries in that Array. Remember, Arrays start numbering their entries at 0; this is why we're checking for `i < something.length` (`i` *less than* `something.length`) instead of `i <= something.length` (`i` less than *or equal to* `something.length`). 3. Then the `// looped code` area happens (which presumably contains actual code instead of just a one-line comment). 4. `i++` happens, which adds 1 to the stored value of `i`. So how does this control flow structure help you walk through an Array and address every element one by one? Because it gives you a variable (named `i`) that's going to loop every whole number from 0 to that Array's `.length - 1` That's perfect: ```js // the next line creates an array let something = ["truck", "train", "aeroplane"]; // as long as i is less than 3, keep looping for (let i = 0; i < something.length; i++) { // we're in the loop now // something[i] is now an element of something // output that element console.log( something[i] ); } ``` But there's a shorter way that's great in most situations. As long as you don't need to `return` anything, you can: ```js let something = ["truck", "train", "aeroplane"]; something.forEach( (item, i) => { // looped code goes here // item is the element of something // i is the "index" of something console.log( item ); }); ``` As shown above, `Array.forEach` takes a callback as an argument. The callback will be called once for each element of `something`. Each time the callback is called, `item` and `i` will be pre-filled with the next element of `something` and the index of that element. (The "index" is the number you'd put between square brackets to get that element.) ### The Increment (`++`) and Decrement (`--`) Operators You'll have noticed that the traditional `for` loop has `i++` as the third statement in its funky signature. This is the "Increment Operator". It adds 1 to the variable it's attached to, assuming it's a number. You can subtract 1 from a variable just as easily, which for example is how you'd do a `for` loop that counts backwards: `i--`. ### `while` Loops Another situation you'll occasionally find yourself in that calls for the Increment Operator in a loop: you want a loop that runs until a condition is met. But you also want a limit to how many times the loop will run -- rather than strictly waiting for that condition to change. This is a job for the `while` loop. ```js let isDone = false; let i = 0; while ( !isDone && i < 10000 ) { isDone = checkStatus(); i++; } ``` We know the `while` loop will run at least one iteration because `i` starts at 0 and `isDone` starts as `false`. Why does that mean at least one iteration? Because after `while` is a conditional that says: evaluate as `true` **if** `isDone` is `false` or evaluates to `false`, **and** `i` is less than 10,000. If the conditional evaluates as `true`, then the loop runs. After that loop, it checks the conditional again, and, if the conditional still evaluates to `true`, the script runs the loop again. We got this result out of the `while` conditional thanks to some new things: the "Logical Not" operator, and the "Logical And" operator (plus we used the "Less Than" comparison operator, covered earlier this lesson). Logical Not inverts whether something will evaluate as true. Logical And allows you to chain together conditional logic; the condition on the left and the condition on the right must both evaluate as true in order for the conditional to evaluate true as a whole. Inside the loop we get the return value of some function called `checkStatus()` which we can assume exists. Hopefully, whoever programmed the code above, checked the return value data type first, and confirmed it eventually outputs something that evaluates as true! We store the return value of `checkStatus` in the variable `isDone` which is the same variable checked in the `while` conditional. Then we increment `i`. Here the loop ends, with control flow now hitting the `while` conditional to see if it's still true. If it's false, control flow skips to the next line after the `while` loop's closing bracket. But if the `while` loop's conditional evaluates as `true` forever, the script will keep running that loop forever, or until someone or something shuts it down. ![I hope the complete lack of connection between pictures and text isn't too jarring](/static/img/mm/space/800px-Extrasolar_planet_NASA3.jpg) ### Lesson Conclusion Manipulating and navigating your data is the essence of programming. Every category of software must manipulate data, and to do that, often, a coder must navigate data structures. There are often situations such that, not only do you have a complex data structure, but you have an array *full* of those structures. Therefore, it's important to understand loops, and know which loop is best for which job. Remember, the traditional `for` loop might be slightly more cumbersome to write out, but it lets you `return` effectively. Today's lesson also unlocked the conditional part of `if` and `while`, by exposing the conditional operators. And not last but least, I explained what the `++` and `--` operators do.

How to Code: The Fundamentals, pt 1

URL copied to clipboard
By AstroMacGuffin dated  last updated 
![Writing code is a lot like having cyber minions](/static/img/mm/cyberspace/onward-cyber-minionsSmall.jpg) As moderator and volunteer on the JavaScript Mastery discord, I've noticed a trend. The people who are in the most distress when they come for help, are the people who jumped head-first into a tutorial that was far too advanced for their skill level. They don't even know the fundamentals of JavaScript and they're trying to build a TikTok clone or a medical-grade messaging app. Some of them don't even want to learn, and are eager to say so. For the rest of you: welcome back to basics. There's a lot of fundamental knowledge you may have missed. If you're not really sure what variables are; if you have no idea how to create a function; and if you've never heard of the terms "control flow" or "scope" before, everything you do will make more sense after you grok this information. If someone (such as myself) sends you this link, congratulations! That person thinks you'll be a better programmer with just a little bit of high-density reading!


People who don't write code might think it's magic, but it's just language, and logic. Anyone can pick it up, because our species excels at both language and logic. So let's do this! If you feel like I skipped some crucial information, maybe try [part 0 of "How to Code: Fundamentals"](https://astromacguffin.com/ref/id/62ee85c9ae620ee833fd88b7). ### This Lesson First you'll learn about control flow and scope. Then you'll learn about variables, a little bit about data types, and then functions. Control flow is a programming concept that means you are in control of which instructions get done in what order. In this lesson we'll mostly be focused on the simplest control flow scheme: line 1 happens, then line 2 happens, then line 3, etc. until the program is complete. I'll use the `if` statement to demonstrate a common control flow feature of programming. Variables are nametags for pieces of data. There are many types of data. Variables are not "typed" in JavaScript, meaning a variable can point to data of one type one moment, and another type of data the next. Functions are nametags for code, but they're also more. Functions take input and send output, and can be any level of complexity, making them entire mini-programs within your program. ### Control Flow "Control flow" refers to things you can do in programming that control which instructions get sent to the CPU in what order. Take your simplest code sample, a traditional Hello World in browser-side JavaScript: ```js const text = 'Hello World'; alert(text); ``` It has two lines of code: 1. The first line of code creates a `const` -- a "constant", which is a type of variable. The `const` named `text` will hold the text, "Hello World". 2. The second line of code calls a function that's built into JavaScript, `alert`. It passes input to that function by placing the variable name `text` between the parentheses. `alert` is a well-known function that pops up a simple message box on the web browser. What should the message say? That's the input you provide when you call the `alert` function. More on functions later. The upshot for now is that, when you run this code, a pop-up, saying "Hello World", should appear. But how does the `alert` function know anything about a variable named `text`? That's thanks to control flow, and scope, a second feature under your control, which will be explained soon. Suffice to say for now: control flow goes from top to bottom, line by line. Since the definition of `text` came before the call to `alert`, `text` existed when `alert` was called. To explain scope better I'll introduce the `if` statement. This code contains a common mistake: ```js let color = 'blue'; if (color === 'blue') { const text = 'Hello World'; } alert(text); ``` What's happening here? First, let me explain *operators*. A single `=` equals sign is known as the "assignment operator". It assigns a value on the right hand side, to a variable on the left. So on the first line of code above, a variable called `color` is being *assigned* the value "blue". But on the next line of code, we have three equals signs `===` back to back. This is one of the many *comparison operators*. The `===` operator means "is exactly equal to". And of course, on that second line of code above, we've met our first `if` statement. If the conditions in the parentheses evaluate to `true`, then the code in the curly braces will be executed. This is a control flow feature. If the code above was run with no modifications, the following line of code would always be executed because `color` will always be exactly equal to "blue" (since we just defined it as such in the line above): ```js const text = 'Hello World'; ``` But since that's all the code in the curly braces after the `if` conditional... what happens next? After any control flow structure in your code has met its end, control flow always resumes its previous state, meaning in this case, we go back to doing things line-by-line, top to bottom... ### Scope ...Which would be great if not for the bug. It's a very common bug: a variable is being used "out of scope". ![robo-mouse-clickSmall.jpg](/static/img/mm/cyberspace/robo-mouse-clickSmall.jpg) Let's look at the whole thing again: ```js let color = 'blue'; if (color === 'blue') { const text = 'Hello World'; } alert(text); ``` If you ran it in a browser, no pop-up box would appear, and you'd be told `Uncaught ReferenceError: text is not defined` in the Developer Tools console. (To open the console, right click almost anywhere in the page, and choose **Inspect** -- e.g. **Inspect element**.) So why isn't `text` defined? It's because it fell out of scope. Basically, each set of curly braces creates a context one level "inner" compared to the context of where you typed those new curly braces. Using our example, the `const text = 'Hello World';` line is in a context one level "inner" vs everything outside those curly braces. **Each of these contexts has its own scope.** Variables from "inner" levels of scope can't be used in "outer" levels of scope. Variables from "outer" levels of scope **can** be used in the "inner" scope code. Just remember, in any given situation, the so-called "outer scope" is often an "inner scope" compared to the overall global scope, that is, the outermost part of the control flow. ***The variable will fall out of scope when the block that created it, ends.*** So long as that doesn't happen before control flow reaches the part of the code where you want to use the variable -- the variable will be available. In the example code, the `if` block ended with the closing curly brace `}` and so the `const text` no longer existed when `alert` was called. That's scope. ### Variables & Data Types Variables (aka vars) are nametags for data. This alone is a powerful feature. Combining variables with other variables, and combining variables with functions, represents almost 100% of programming, so this section is critical. Someone recently asked in the JavaScript Mastery discord why variables were important, so here's a bullet list of reasons off-the-cuff: - Configuration (the easiest config system for any piece of software is a list of config vars at the top) - Software Speed (when the same value is referenced multiple times, a variable is faster) - Function Arguments (without which functions would be far less powerful) - Readability (even if you're the sole maintainer of a program, you'll thank yourself later if your code is readable) - Debugging Steps (easier to find the mistake in your code if that mistake leaves a named imprint you can output) First thing you need to know is the three types of variable, identified by the keyword used to declare them: `const`, `let`, and `var`. - `const` - The variable must be defined. Can't be changed. Normal scope rules apply. - `let ` - The variable need not be defined. Can be changed. Normal scope rules apply. - `var ` - The variable need not be defined. Can be changed. Special scope rules apply. #### Declaring & Defining Variables In JavaScript, as with most languages, you have to *declare* a variable before you can use it. You declare a variable by issuing one of the above three keywords, plus the variable's name. ```js let foo; var bar; ``` You can go one step further in the same line, *defining* the variable by using the assignment operator and some value on the right of that. ```js let foo = 2; var bar = 'The quick brown fox jumped over the lazy dog.'; ``` Variables made with `const` must always be declared and defined at the same time. ```js const foobar = 'Two quick brown foxes jumped over three lazy dogs.'; ``` #### Why `var` is Useless So what are these "special scope rules" attached to `var`? I'll borrow the example from [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var): ```js var x = 1; if (x === 1) { var x = 2; console.log(x); // expected output: 2 } console.log(x); // expected output: 2 ``` The special scope rule is that `var` does nothing special. You still have to declare the variable in the outside scope, and even the second `var` in the `if` block (`var x = 2;`) offers no special features. Compare the above, to the below: ```js let x = 1; if (x === 1) { x = 2; console.log(x); // expected output: 2 } console.log(x); // expected output: 2 ``` They're practically identical (the second example is shorter by one keyword) and they get the same result. For this reason, JavaScript coders tend to drift toward *never* using `var`. Just remember: `const` for constants that can't be changed, `let` for everything else. In all cases, you need to remember to declare your variables in proper scope, so that the variable will be available when it's needed, and released from memory when it's not needed anymore. ### Data Types Variables in JavaScript both do, and don't, have a "type". Every piece of data has a "data type", and yet, variables are not "strongly typed" in JavaScript -- meaning any variable can point to any type of data -- no variable is locked into the type of data it was first assigned. Still, data types are important; eventually, you will find yourself often querying the data type of a variable as part of an `if` or `switch` statement, to make more powerful functions. Long story short, we need a quick word on data types. For a beginner, here's what you need to know about types. There are two categories. Category 1: "primitives" - Data type `boolean` stores either `true` or `false` - Data type `string` stores text of whatever length - Data type `number` will be reported for every number you'll ever use - `null` and `undefined` data types, explained in the next lesson Category 2: "objects" - variables created using the `let obj = new className()` syntax - variables created using the `let obj = { field: 'value', property: 1 }` syntax - arrays, regular expressions, etc Why care? Because category 2, the objects, are always handled "by reference". This means if you assign it to another variable, both variables point to the same object, as shown here: ```js let foo = { field: 'value', property: 1 }; // foo.property is currently 1 const bar = foo; bar.property = 2; console.log(foo.property); // output is 2 ``` Only the object types do this. ![green_computer-gutsSmall.jpg](/static/img/mm/cyberspace/green_computer-gutsSmall.jpg) ### Functions Functions give nametags to code, but also much more. Functions can take input, and can send output, like little mini-programs. Most of the best functions are small, single-task functions. Let's take a look at a simple function that has both input and output: ```js function add(a, b) { return a + b; } ``` The function is called `add` and it adds two numbers, that are given to it when it's called (the inputs). It adds the two numbers, returning (outputting) the result. Let's break this down. Obviously `function add` creates a function called *add*. The `(a, b)` is where things get interesting. This is called the function's "signature". This is how you define the inputs for the function. In this example, we're defining two variables, `a` and `b`, that will be available inside the function. The values of `a` and `b` depend on whoever writes code "calling" this function. (You "call" a function by typing its name with a set of parentheses after it.) For example, if someone writes: ```js let c = add(6, 18); ``` ...then, inside the function, `a` will equal 6 and `b` will equal 18. Notice that the person calling the function used the same number of inputs as the signature specified. And the last thing to understand about the function definition for `add`, is the line starting with `return`. The `return` statement is a function's output. If the function is used thusly: `let c = add(6, 18);` ...you might notice the `let c =` part and wonder, how does it know what `c` should equal? It knows because of the `return` statement inside the function. This example, our `add` function, doesn't even create a variable to return -- it just returns the direct result of a math operation. Outputting values of whatever complexity in this way is fine. ![earth-hexgrid.jpg](/static/img/mm/cyberspace/earth-hexgrid.jpg) Let's look at a slightly more complex example. Let's say you have a simple project for logging and storing log entries. ```js const ERR_LOGSTOR = 'Invalid storage medium'; // an error message const logStorage = []; // an array where we store our logs // function signature with a default value function storeLog(logMessage='Message not specified') { if (Array.isArray(logStorage)) { logStorage.push(logMessage); return 0; } else { return ERR_LOGSTOR; } function logMessage(logMessage=undefined) { if (logMessage === undefined) { console.log('An undefined message was not logged'); } else { console.log(logMessage); const status = storeLog(logMessage); if (status === ERR_LOGSTOR) { console.warn('Log storage error: ' + status); } } } logMessage('System started'); ``` Let's break that down: ```js const ERR_LOGSTOR = 'Invalid storage medium'; // an error message ``` Whenever you see two slashes `//` it means that the rest of that line is a "comment". This is how programmers put documentation into the code itself. Code can also be "commented out" by putting two slashes at the beginning of the line. Code that's been "commented out" is completely ignored when you run the program. ```js const logStorage = []; // an array where we store our logs ``` Two square brackets `[]` means "create a new, empty array". So when we begin this program, `logStorage` will be assigned an empty array. ```js function storeLog(logMessage='Message not specified') { ``` This is the function declaration and the beginning of its definition. The signature is one value this time, but the value has a default. Since the value has a default, you can skip that part of the signature when calling the function: it could be `storeLog('I am a log message')` or it could be `storeLog()` with nothing between the parentheses. If nothing is between the parentheses, the function will proceed as if you had typed `storeLog('Message not specified')`. ```js if (Array.isArray(logStorage)) { logStorage.push(logMessage); return 0; } else { return ERR_LOGSTOR; } ``` In the above snippet, first we do a sanity check -- meaning we check the code's situation to avoid producing an error. In this case, that means making sure the `logStorage` variable is an Array. If it is, we add the `logMessage` to the end of the `logStorage` array and output a 0 as our function's return value. If `logStorage` is not an Array, we do nothing except return the error message defined at the top of the script. A quick additional note about `return`: using `return` also exits control flow from the function, in addition to sending output. Notice you can have multiple `return` statements in a function. Control flow will only arrive at one of them, but you can manage this with features like the `if` statement. ```js } ``` This ends the function. Every code block begins with `{` and ends with `}`. This applies to control flow structures such as the `if` statement, as well as functions, classes, etc. ```js function logMessage(logMessage=undefined) { ``` Once again we have a function declaration with a single parameter as its signature, and once again the parameter has a default value. ```js if (logMessage === undefined) { console.log('An undefined message was not logged'); } ``` Here we're doing some error trapping: we don't want to log nothing, but we do want to log the fact that nothing was logged. (Ah, business logic.) ```js else { console.log(logMessage); ``` Whenever you use `if`, you can use `else` right after the `if` block ends. The `if` block executes if the condition in parentheses is true; the `else` block runs otherwise. ```js const status = storeLog(logMessage); ``` Here we're using the previous function, `storeLog`. Yes, you can use functions within functions. If doing task A means also doing task B, you'll probably find yourself calling one function from within another. ```js if (status === ERR_LOGSTOR) { console.warn('Log storage error: ' + status); } ``` When we ran the `storeLog` function we also grabbed its return value. Now we're checking it against our known error messages, and if there was a match, we're warning the console operator there was a problem. ```js } } ``` Here we're closing the `else` case and closing the function. ```js logMessage('System started'); ``` Finally we set off the whole chain of events by calling `logMessage` to log a message that the system has started. Move on when you're ready to [part 2 of "How to Code: The Fundamentals"](https://astromacguffin.com/ref/id/62ec1c6a209885383e63d857).
🔍

Valid HTML!Valid CSS!Powered by Node.js!Powered by Express.js!Powered by MongoDB!