├── .prettierignore
├── LICENSE
├── README.md
├── VSCodeTips
├── README.md
└── assets
│ ├── create-html.gif
│ ├── empty-project-folder.png
│ ├── extensions-icon.png
│ ├── index-js.png
│ ├── open-folder.png
│ ├── search-and-replace.png
│ ├── settings-panel.png
│ └── spell-checker.png
└── fundamentals
├── CLI.md
├── DOM_manipulation.md
├── README.md
├── XMLHttpRequest.md
├── array_manipulation.md
├── assets
├── box.png
├── call-stack.png
├── do-while.png
├── event-loop-1.png
├── event-loop-2.png
├── event-loop-3.png
├── event-loop-4.png
├── event-loop-5.png
├── express.png
├── map-filter-reduce-emoji.png
├── prototype.png
├── prototypes-fundamental.png
├── reduce-bucket.png
├── scopes.png
└── sync-async.png
├── async_await.md
├── bug-challenge-es6
├── .babelrc
├── .gitignore
├── __tests__
│ └── bug-challenge-tests.js
├── bug-challenge.js
├── jest-helpers.js
└── package.json
├── code_commenting.md
├── code_formatting.md
├── conditional_execution.md
├── event_loop.md
├── exercises.md
├── express.md
├── functions.md
├── homework_pr.md
├── javascript_review.md
├── loops.md
├── map_filter.md
├── names_of_special_characters.md
├── naming_conventions.md
├── objects.md
├── oop_classes.md
├── operators.md
├── promises.md
├── scope.md
├── scope_closures_this.md
├── statements_expressions.md
├── this.md
├── try_catch.md
├── values.md
└── variables.md
/.prettierignore:
--------------------------------------------------------------------------------
1 | *.md
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This work is licensed under the Creative Commons Attribution 4.0 International License.
2 | To view a copy of this license, visit http://creativecommons.org/licenses/by/4.0/
3 | or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | >Please help us improve and share your feedback! If you find better tutorials or links, please share them by opening a Pull Request.
2 |
3 | # Fundamentals
4 |
5 | |Week|Topic|
6 | |----|-----|
7 | |1.|Git|
8 | |2.|• Intro JavaScript (What is it, where can you use it for) • [Variables (var, let, const)](fundamentals/variables.md) • [Basic Data types (Strings, Numbers, Arrays, Booleans)](fundamentals/values.md) • [Operators](fundamentals/operators.md) • [Special characters and their names](fundamentals/names_of_special_characters.md) • [Naming conventions](fundamentals/naming_conventions.md)|
9 | |3.|• Git work flow :smiling_imp: • [Advanced data types (objects)](fundamentals/objects.md) • [Conditional execution](fundamentals/conditional_execution.md) • [Statements vs Expressions](fundamentals/statements_expressions.md) • [Loops (for/while)](fundamentals/loops.md) • [Functions](fundamentals/functions.md) • [Scope](fundamentals/scope.md)|
10 | |4.|• Capturing user input • Events • [Basic DOM manipulations (img src, innerHTML)](fundamentals/DOM_manipulation.md) • Code debugging using the browser • [Code commenting](fundamentals/code_commenting.md) • Structuring code files • [Code formatting](fundamentals/code_formatting.md) • [Homework Pull Request Workflow](fundamentals/homework_pr.md)|
11 | |5.|• Functions + JSON/Arrays • [Array Manipulations](fundamentals/array_manipulation.md) • JSON • [Map and filter](fundamentals/map_filter.md) • Arrow functions |
12 | |6.|• [Closures](fundamentals/scope_closures_this.md) • Callbacks|
13 | |7.|• Structure for a basic SPA (Single Page Application) • [XMLHttpRequests](fundamentals/XMLHttpRequest.md) • API calls|
14 | |8.|• [Event Loop (order of execution)](fundamentals/event_loop.md) • [Promises](fundamentals/promises.md) |
15 | |9.|• [try...catch](fundamentals/try_catch.md) • [async/await](fundamentals/async_await.md) • [Object Oriented Programming and Classes](fundamentals/oop_classes.md) • [The `this` keyword](fundamentals/this.md) |
16 |
17 | *The HackYourFuture curriculum is subject to CC BY copyright. This means you can freely use our materials, but just make sure to give us credit for it :)*
18 |
19 | This work is licensed under a Creative Commons Attribution 4.0 International License.
20 |
--------------------------------------------------------------------------------
/VSCodeTips/README.md:
--------------------------------------------------------------------------------
1 | # VSCode Tips
2 |
3 | ## Installation
4 |
5 | Download and install the appropriate version of VSCode for your operating system from the [VSCode web site](https://code.visualstudio.com/).
6 |
7 | ## Some useful extensions
8 |
9 | VSCode can be extended with _extensions_.
10 |
11 | > There are many extensions available that you could possibly install. Browsing through the long list of the VSCode Extensions Marketplace might make you feel like a child in a candy store, with all this free stuff ready for the taking. However, we urge you to resist the temptation and just install the extensions recommended below. Other extensions may interfere with the essential ones recommended here. Once you gain more experience you may choose to install additional ones, but in all cases you should only do so when you have an immediate, identifiable use case for each one.
12 |
13 | There are four extension that we recommend you install from day 1.
14 |
15 | 1. **Code Spell Checker**. We fully understand that you guys sometimes have difficulty with the correct English spelling when choosing names for variables and functions in your JavaScript programs. That is nothing to be ashamed of, but why not get some help from a handy extension?
16 |
17 | 2. **ESLint**. This extension can check your JavaScript code for obvious errors, such as undefined variables, unused variables, etc.
18 |
19 | 3. **Prettier - Code formatter**. Prettier is an code formatter that enforces a consistent style by parsing your code and re-printing it with its own rules that take the maximum line length into account, wrapping code when necessary.
20 |
21 | > If you have any other code formatter extensions installed, e.g., **Beautify**, be sure to remove them as they may conflict with **Prettier**.
22 |
23 | 4. **Live Server**. Launch a development local Server with live reload feature for static & dynamic pages.
24 |
25 | ### VSCode Setup Instructions
26 |
27 | 1. Start up VSCode.
28 |
29 | 2. Press the button in the area in the left margin (called the **Activity Bar**), as shown below:
30 |
31 | 
32 |
33 | 3. In the input field in the upper left corner, type `spell checker` as pictured here:
34 |
35 | 
36 |
37 | 4. Press the `Install` button of **Code Spell Checker**.
38 |
39 | 5. Install the remaining extensions by repeating steps 3 and 4, by typing the names of the extensions:
40 |
41 | - **ESLint**
42 | - **Prettier - Code formatter**
43 | - **Live Server**
44 |
45 | 6. You now need to install a global Node package to support ESLint. Open a terminal window in VSCode by selecting **View**, **Integrated Terminal** from the menu bar.
46 |
47 | 7. A terminal window opens in the lower half of the VSCode window. In this window, type the command below (on Linux and MacOS systems you may need to prefix this command with `sudo`, e.g. `sudo npm ...`):
48 |
49 | ```text
50 | npm install -g eslint
51 | ```
52 |
53 | ## Customise VSCode Settings
54 |
55 | We recommend that you apply a couple of changes to the default settings of VSCode to help you create well-formatted JavaScript code. Follow these steps:
56 |
57 | 1. Press the function key F1 and type the following in the text box:
58 |
59 | ```text
60 | open settings
61 | ```
62 |
63 | A menu will appear with matching menu options:
64 |
65 | 
66 |
67 | 2. Select **Preferences: Open User Settings (JSON)** from the list
68 |
69 | 3. Copy the content shown below and paste it over (i.e. replace) the existing content.
70 |
71 | ```json
72 | /// Place your settings in this file to overwrite the default settings
73 | {
74 | "editor.detectIndentation": false,
75 | "editor.formatOnSave": true,
76 | "editor.minimap.enabled": false,
77 | "editor.tabSize": 2,
78 | "editor.codeActionsOnSave": {
79 | "source.fixAll": "explicit"
80 | },
81 | "files.autoSave": "onFocusChange",
82 | "prettier.trailingComma": "es5",
83 | "editor.defaultFormatter": "esbenp.prettier-vscode",
84 | "[javascript]": {
85 | // override possible JavaScript specific user setting
86 | "editor.defaultFormatter": "esbenp.prettier-vscode"
87 | },
88 | "editor.bracketPairColorization.enabled": true,
89 | "editor.guides.bracketPairs": true,
90 | "editor.guides.highlightActiveIndentation": true,
91 | "editor.guides.bracketPairsHorizontal": "active"
92 | }
93 | ```
94 |
95 | 4. Close the Settings tabs.
96 |
97 | ## Configuring the Default Shell (Windows users only)
98 |
99 | By default, a VSCode installation on Window uses **PowerShell** for the Integrated Terminal. To change this to **Git Bash**, follow these steps:
100 |
101 | 1. Press the key combination F1 to open the VSCode Command Pallette.
102 | 2. Type the words: `select default`
103 | 3. From the drop-down menu, select **Terminal: Select Default Profile**
104 | 4. A new drop-down menu will appear. From this menu, select **Git Bash**.
105 |
106 | ## Using VSCode
107 |
108 | You’ll get the most out of VSCode if you organise your work in **project folders**.
109 |
110 | Later in the course you will be “cloning” Git repositories into local folders as the basis for your homework or projects. But for now, if you do not yet have a project folder you should create one first.
111 |
112 | A nice way to organise your project folders is to create a parent folder where you will keep all project folders. For instance, you could create a `hackyourfuture` folder in your home directory to serve as the parent directory. Then, inside that parent directory, create a project folder, say `my-first-project`.
113 |
114 | > Note: Do not use spaces in file and folder names. Names with spaces often require special treatment ("quoting") when referring to them in the command line and this is best avoided.
115 |
116 | Once you have created the project folder you have two options to open VSCode. If you are on the command line you can `cd` to your project folder and type the command:
117 |
118 | ```text
119 | code .
120 | ```
121 |
122 | Alternatively, you can first open VSCode application and then use the **Open Folder** button or the **File, Open Folder...** menu command to open the project folder.
123 |
124 | 
125 |
126 | > Make it a habit in VSCode to always open the main folder that contains the project you are working on, rather than individual files or subfolders inside that folder.
127 |
128 | In the figure below the folder named `my-first-project` was opened in VSCode. The directory tree (still empty) for that folder in shown in the **Explorer** panel. The folder name `MY-FIRST-PROJECT` is displayed in uppercase in the title bar of the directory tree panel.
129 |
130 | 
131 |
132 | ## Creating a new HTML file
133 |
134 | You are now ready to start adding your first HTML file.
135 |
136 | 1. Open the folder where you will keep your working files, for instance `my-first-project`.
137 |
138 | 2. Right-click in an empty space in the `EXPLORER` window and select **New File** from the context menu, or alternatively, click on the `New File...` button as shown in the screen animation below. Then, type the name of the file, `index.html` and press Enter.
139 |
140 | 
141 |
142 | As can be seen in the animation, you can quickly create a skeleton HTML file by typing an exclamation mark followed by pressing the Tab key.
143 |
144 | 3. To complete the files for your first project, create an `index.js` to contain your JavaScript code. A simple file with rudimentary DOM manipulation might look like this:
145 |
146 | 
147 |
148 | 4. To try it out in a browser, right click on the `index.html` file in the `EXPLORER` window and select the **Open with Live Server** menu option.
149 |
150 | Notes:
151 |
152 | - Be on the watch out for coloured squiggly underlines in your code. These are warnings from either **ESLint** or the **Spell Checker** that something might be wrong. If you see such squiggly underlines, hover your mouse pointer over the underlined text and a tooltip will appear that explains what might be wrong.
153 |
154 | - You can also open the `PROBLEM` panel by selecting **View**, **Problems** from the menu to inspect the reported problems, if any.
155 |
156 | - The left-hand part of the VSCode status bar gives an indication of the number of errors and warnings issued.
157 |
158 | | Symbol | Meaning |
159 | |:------:|----------|
160 | | ⨂ _n_ | Number of errors |
161 | | ⚠ _n_ | Number of warnings |
162 |
163 | ## Some Useful Shortcut Commands
164 |
165 | In the previous section we frequently referred you to the menu bar to select commands. As you get more proficient with VSCode you may want to inspect these menus a little closer and take note of the short-cut commands listed in their right margin. For example, the short-cut command for **File**, **New** is listed as Ctrl+N (press `Ctrl` and `N` keys simultaneously) on a Windows or Linux PC and ⌘N on a Mac.
166 |
167 | Here are some shortcut commands that you will use many times a day and that we recommend you familiarise yourself with from day 1:
168 |
169 | | Operation | Windows | Mac | Linux |
170 | | ---------------------------------------------------------------- | ----------- | --- | ------------ |
171 | | **Format Document** (make it pretty) | Shift‑Alt‑F | ⇧⌥F | Ctrl‑Shift‑I |
172 | | **Search** (Find) | Ctrl+F | ⌘F | Ctrl+F |
173 | | **Replace** (Find and replace) | Ctrl+H | ⌥⌘F | Ctrl+H |
174 | | **Rename Symbol** (change all names in file to a different name) | F2 | F2 | F2 |
175 | | Open an **Integrated Terminal** window in VSCode | Ctrl+' | ⌃\` | Ctrl+' |
176 |
177 | - **Format Document**. This command reformats your JavaScript file in a generally accepted standard format, using proper indenting, proper use of spaces, placing of curly braces and more. A neatly formatted document helps you to better understand your own code and your teachers, mentors and fellow students will love your for it too when they review your work.
178 |
179 | _With VSCode at your finger tips there is no longer any excuse for submitting poorly formatted homework!_
180 |
181 | - **Search**. Search for specified text.
182 | - **Replace**. Replace specified text by some other text.
183 |
184 | In the figure below the **Replace** pop-up window is shown. The **Search** pop-up is similar, but with one input field only.
185 |
186 | 
187 |
188 | - The `Aa` button activates the **Match Case** option.
189 | - The `ab` button matches **Whole Words Only**.
190 | - The `.*` button allow you to search using _regular expressions_, which you may encounter in later modules as an advanced JavaScript programming topic.
191 | - The `b-C` button next to the second input field replaces the next occurrence of the matched text.
192 | - The adjacent `ab-BC` button replaces **all** occurrences of the matched text.
193 | - The up and down arrows move the cursor to the previous and next match.
194 | - To get rid of the pop-up press `Esc` or press the `x` button.
195 |
196 | - **Rename Symbol**. This command renames all occurrences of a JavaScript variable or function name. To do so, move the text cursor to the variable or function name and press F2. A small pop-up window will appear in which you can type a new name. Press Enter to finalise the change or Esc to cancel it.
197 |
198 | - **Open an Integrated Terminal window**. We already covered this when we mentioned the **View**, **Integrated Terminal** menu command.
199 |
200 | >For a complete list of VSCode keyboard shortcuts, select the **Help, Keyboard Shortcuts Reference** command from the VSCode menu. This will take you to an online PDF file with keyboard shortcuts specifically for your computer platform type.
201 |
202 | ### Further information
203 |
204 | Please note that VSCode is actively being developed. At present there is a monthly release cycle, so don't be surprised when you are prompted once a month to update to the latest version. We advise you to update when prompted (naturally, not when you are in the middle something that you don't want interrupted).
205 |
206 | You can find detailed information about VSCode at the [VSCode web site](https://code.visualstudio.com/docs).
207 |
--------------------------------------------------------------------------------
/VSCodeTips/assets/create-html.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/VSCodeTips/assets/create-html.gif
--------------------------------------------------------------------------------
/VSCodeTips/assets/empty-project-folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/VSCodeTips/assets/empty-project-folder.png
--------------------------------------------------------------------------------
/VSCodeTips/assets/extensions-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/VSCodeTips/assets/extensions-icon.png
--------------------------------------------------------------------------------
/VSCodeTips/assets/index-js.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/VSCodeTips/assets/index-js.png
--------------------------------------------------------------------------------
/VSCodeTips/assets/open-folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/VSCodeTips/assets/open-folder.png
--------------------------------------------------------------------------------
/VSCodeTips/assets/search-and-replace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/VSCodeTips/assets/search-and-replace.png
--------------------------------------------------------------------------------
/VSCodeTips/assets/settings-panel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/VSCodeTips/assets/settings-panel.png
--------------------------------------------------------------------------------
/VSCodeTips/assets/spell-checker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/VSCodeTips/assets/spell-checker.png
--------------------------------------------------------------------------------
/fundamentals/CLI.md:
--------------------------------------------------------------------------------
1 | # CLI
2 |
3 | ## Most used commands
4 |
5 | | Command | Description |
6 | | ------- | ----------- |
7 | | `pwd` | present working directory |
8 | | `ls` | List files in the directory |
9 | | `cd` | change the directory |
10 | | `touch` | Create an empty file |
11 | | `echo` | display the string |
12 | | `echo -n` | Display the string without newline |
13 | | `echo “something” > file` | Redirect the output of echo and create file |
14 | | `echo “another thing” >> file` | Append the string to the file |
15 | | `mkdir` | make a new directory |
16 | | `cd ~` | home |
17 | | `cd -` | previous directory |
18 | | `cd ..` | parent directory |
19 | | `ls -a` | List all files including hidden files |
20 | | `cd /` | change to the root directory |
21 | | `cat` | Concatenate the file line by line and display it on the terminal |
22 | | `less` | Print the big file line by line |
23 | | `vim ` | open the editor with `` {`a:` to go to the insert mode, ` :wq` to write and quit } |
24 | | `for var in {START..END}; do ; ;..; ; done` | |
25 | | `head ` | display the first 10 lines of file |
26 | | `tail ` | display the last 10 lines of file |
27 | | `head -n ` | display first n lines of file |
28 | | `tail -n ` | display last n lines of file |
29 | | `man ` | Display manual of the COMMAND |
30 |
--------------------------------------------------------------------------------
/fundamentals/DOM_manipulation.md:
--------------------------------------------------------------------------------
1 | # Basic DOM manipulation
2 |
3 | The Document Object Model (DOM) is a construct through which web browsers make the HTML structure of a web page (= 'document') available to JavaScript files loaded into that page. We can access the DOM through a global object called `document`.
4 |
5 | Consider this HTML:
6 |
7 | ```html
8 |
9 |
10 |
11 | ```
12 |
13 | A common method to access an HTML element through the DOM is by giving it an ID, and then using the `document` method `getElementById()`.
14 |
15 | ```js
16 | const rootDiv = document.getElementById('root');
17 | ```
18 |
19 | Now, we have a *reference* to the HTML element in our JavaScript code. We can, for instance, set the text content through the `innerText` property.
20 |
21 | ```js
22 | rootDiv.innerText = 'Hello, world!';
23 | ```
24 |
25 | As a result, the HTML structure now looks like this:
26 |
27 | ```html
28 |
29 |
Hello, world!
30 |
31 | ```
32 |
33 | > See the result of what this code changes in this [CodePen](https://codepen.io/remarcmij/pen/VEerRP) and play with it yourself.
34 |
35 | _Note that we are not modifying the HTML file (e.g., `index.html`) itself. We are just modifying an in-memory representation of the HTML as was initially loaded through the HTML file._
36 |
37 | We can also create elements:
38 |
39 | ```js
40 | // Create a button element and label it Click Me!
41 | const myButton = document.createElement('button');
42 | myButton.innerText = 'Click Me!';
43 | ```
44 |
45 | This creates a button element and sets its label (i.e. `innerText`), but this in itself is not enough. At this point the button is created but not yet added to the DOM: it is still somewhere "hanging up in the air". We need to attach it to some parent element that is already part of the DOM. This is done by calling `appendChild()` on that parent element, passing it a reference to the newly created element.
46 |
47 | ```js
48 | rootDiv.appendChild(myButton);
49 | ```
50 |
51 | As a result, the HTML structure now looks like this:
52 |
53 | ```html
54 |
55 |
56 |
57 |
58 |
59 | ```
60 |
61 | > See the result of what this code changes in this [CodePen](https://codepen.io/remarcmij/pen/bmEaVm) and play with it yourself.
62 |
63 | We can set attributes on elements:
64 |
65 | ```js
66 | myButton.setAttribute('class', 'my-button');
67 | ```
68 |
69 | Resulting HTML:
70 |
71 | ```html
72 |
73 |
74 |
75 |
76 |
77 | ```
78 |
79 | > See the result of what this code changes in this [CodePen](https://codepen.io/remarcmij/pen/wYMmpP) and play with it yourself.
80 |
81 | We can add event listeners to elements to respond to user interaction. In this example we are adding an event listener to the button that responds to the `click` event. This event is triggered whenever the user clicks on the button.
82 |
83 | ```js
84 | myButton.addEventListener('click', function () {
85 | const para = document.createElement('p');
86 | para.innerText = 'You clicked me!';
87 | rootDiv.appendChild(para);
88 | });
89 | ```
90 |
91 | Adding an event listener does not change the HTML structure. However the event listener may cause changes to the DOM (as is illustrated in the above example) when the event is triggered.
92 |
93 | > See the result of what this code changes in this [CodePen](https://codepen.io/remarcmij/pen/MPKVEP) and play with it yourself.
94 |
95 |
--------------------------------------------------------------------------------
/fundamentals/README.md:
--------------------------------------------------------------------------------
1 | # Understanding JavaScript fundamentals
2 |
3 | When talking about JavaScript, it is important that you use the correct terminology. This way, if you talk about code with others, they'll understand what you mean without any ambiguity.
4 |
5 | ## Variables
6 |
7 | A "variable" is a place where you can store information, such as a string, or a number.
8 |
9 | ### Variable declaration
10 |
11 | Variables are "declared" using the `let` and `const` keywords (or the older `var` keyword):
12 |
13 | ```js
14 | let x = 5;
15 | ```
16 |
17 | Here, we say: "declare variable x and initialize it with the number 5".
18 |
19 | ### Variable types
20 |
21 | All variables have a type. In our example above, the variable `x` is a `number`. JavaScript supports the following types:
22 |
23 | * `string`, e.g. "HackYourFuture"
24 | * `number`, e.g. 5, or 10.6
25 | * `boolean`, e.g. `true` or `false`
26 | * `array`\*, e.g. `[1, 2, 3]` or `['what', 'is', 'your', 'name']`
27 | * `object`, e.g. `{name: 'John', age: 24}`, or the special object `null`
28 | * `function`, e.g. `function () { return 4; }`
29 | * `symbol`
30 |
31 | In addition, a variable may be `undefined`. This is also a special type.
32 |
33 | To get the type of a variable, use the following code:
34 |
35 | ```js
36 | let x = 5;
37 | let typeOfX = typeof x; // -> "number"
38 | ```
39 |
40 | Note that I've put an asterisk behind 'array'. That is because in JavaScript, array is a special kind of object:
41 |
42 | ```js
43 | let arr = [1, 2, 3];
44 | let typeOfArr = typeof arr; // -> "object"
45 | ```
46 |
47 | However, in our communication, we will call these variables arrays.
48 |
49 | ### Null & undefined
50 |
51 | The values `null` and `undefined` are very similar in JavaScript, but they behave a bit differently. The difference is that `null` always has type "object", and `undefined` always has type "undefined".
52 |
53 | Whenever you declare a variable, but you don't set a value, the variable will become `undefined`. JavaScript will never make a variable `null` unless you explicitly program it.
54 |
55 | ```js
56 | let x;
57 | console.log(typeof x); // -> "undefined"
58 | ```
59 |
60 |
61 | ## Arrays
62 |
63 | Variables that are arrays contain a list of things, instead of just one thing. What's inside the array, we typically call "elements". So, the array `[1, 2, 3]` has three elements. The array `[]` has no elements and is therefore empty. The number of elements in an array is called its "length".
64 |
65 | When you want to access an element inside an array, you use an "index". This is the number that you put between brackets (`[]`).
66 |
67 | Given the following code:
68 |
69 | ```js
70 | let arr = ['john', 'jane', 'jack'];
71 | console.log(arr[0]);
72 | ```
73 |
74 | The number `0` is the "index of the first element of array `arr`". Conversely, the element "at index 0 in array `arr` is `'john'`".
75 |
76 | Instead of a number, you can also use a variable to access elements in an array, *as long as this variable is a number*:
77 |
78 | ```js
79 | let arr = ['john', 'jane', 'jack'];
80 | let a = 1;
81 | console.log(arr[a]); // -> jane
82 | ```
83 |
84 | If the index you use is not an integer (a whole number), or if it's less than `0` or if it's greater than or equal to the array's length, you will get back `undefined`.
85 |
86 |
87 |
88 | ## Objects
89 |
90 | Variables that are objects also contain a list of things, but instead of them being in some specific order, they can be assigned to words, called "keys". Instead of "elements" the things that are inside objects are called "properties".
91 |
92 |
93 | ```js
94 | let obj = {name: 'John', age: 24};
95 | ```
96 |
97 | This object has two properties: `name` and `age`. The "value" of the property `name` is the string `'John'`. The "value" of the property `age` is the number `24`.
98 |
99 | When accessing object properties, you can use the dot-notation: `obj.name` or the bracket-notation: `obj["name"]`. Note that the latter looks a lot like the way to access array elements. However, here what's inside the bracket (called "key" for objects, instead of "index") must be a string.
100 |
101 | ```js
102 | console.log(obj.name); // -> 'John'
103 | console.log(obj['name']); // -> 'John'
104 | ```
105 |
106 | Just like with arrays, you can also use a variable to access properties, as long as these variables are strings. In this case you cannot use the dot-notation!
107 |
108 | ```js
109 | let ageKey = 'age';
110 | console.log(obj[ageKey]); // -> 24
111 | ```
112 |
113 | Remember that there is a very big difference between `obj[name]` and `obj["name"]`.
114 |
115 | > Note:
116 | >
117 | > Thinking back of arrays, the length of an array can be retrieved by `arr.length`. So as mentioned before, arrays are just like other JavaScript objects. You could even write `arr['length']` to access the `length` property of the array. JavaScript will look: is what we put between brackets a number? Then it is an index and we'll look up the correct array element. If it's a string, it's a key and we will look up the corresponding property.
118 |
119 |
120 | ## Functions
121 |
122 | A function is a reusable piece of code. Functions are *very* important in JavaScript, to the extent that some people call JavaScript a "function-oriented" language. As mentioned above, variables can be of type function. In fact, *every function is a variable*.
123 |
124 | The following two pieces of code have the exact same result:
125 |
126 | ```js
127 | function sum(a, b) {
128 | return a + b;
129 | }
130 | ```
131 |
132 | and
133 |
134 | ```js
135 | let sum = function (a, b) {
136 | return a + b;
137 | }
138 | ```
139 |
140 | > Note
141 | >
142 | > This is not entirely true, as in the second code, the function is "anonymous", i.e. it has no name. But in both cases, you can call the function like this: `sum(4, 5)`.
143 |
144 | ### Parameters & arguments
145 |
146 | When writing `function sum(a, b)`, `a` and `b` are the "parameters" of the function. We say that this function has two parameters. (Sometimes, you'll see the word "arity": this function has "arity" 2, but that is something you don't have to use for now.)
147 |
148 | Now, when *calling* function sum, e.g. `let s = sum(4, 5);`, we say that the numbers `4` and `5` are the "arguments" of the function. Arguments are "passed" to the function: "we pass `4` and `5` to the function `sum`".
149 |
150 | So remember the difference between the word "parameter" and "argument". Many people confuse them, and that's not a big problem, but understanding the difference is always nice:
151 |
152 | * A parameter is the name you want to give to the variable that is available inside of the function.
153 | * An argument is the actual value you want to assign to the parameters when you call the function.
154 |
155 | A function that "has two parameters" is also said to "take/accept two arguments". But, sometimes you'll hear people say: "the function has two arguments" or "the function takes two parameters". While formally incorrect, you'll know what they mean.
156 |
157 | ### Calling a function on something
158 |
159 | In JavaScript, you can call functions *on* something. By this, we mean that you use the dot to call the function. For instance, when we say "call method `trim` on string `s`", we mean:
160 |
161 | ```js
162 | let s = " this is a string ";
163 | s.trim(); // -> "this is a string"
164 | ```
165 |
166 | > Note
167 | >
168 | > Technically, this means that the string `s` will become the `this` special variable inside of the function.
169 |
170 | However, there are functions that you don't call on anything:
171 |
172 | ```js
173 | function sum(a, b) { return a + b; }
174 | sum(4, 5); // -> 9
175 | ```
176 |
177 | Here, you call the function `sum` on nothing.
178 |
179 | Most built-in functions in JavaScript, like math functions or logging functions, also use the dot:
180 |
181 | ```js
182 | Math.round(4.5);
183 | console.log("hello");
184 | Array.from([1, 2, 3]);
185 | ```
186 |
187 | Indeed, these functions are also called "on" `Math`, `console`, `Array`, and so on. However, in this case, their purpose is more to group them logically, so here it's not very important to use that terminology. We'd rather say: "call the function `Math.round` with `4.5` as an argument", i.e. we include it in the full name of the methods.
188 |
189 | It's more when you think about which functions you can call "on" your own variables (strings, arrays, numbers, etc):
190 |
191 | ```js
192 | myString.trim();
193 | myArray.slice();
194 | myNumber.toString();
195 | ...
196 | ```
197 |
198 |
199 | ## Statements & expressions
200 |
201 | Most programming languages that you'll encounter in real life are called "imperative" programming languages. JavaScript is such an imperative programming language. Imperative is another word for command-like. That is, you give the computer a bunch of commands after each other. First do this, then do that, etc.
202 |
203 | These individual commands are called "statements" in imperative programming languages. You can compare them with sentences in the English language. They have a use by themselves, and do not need something else. "The man eats bread." is a full sentence, it conveys a meaning by itself. A sentence in English is always terminated by a period.
204 |
205 | Similarly, a statement in JavaScript should provide a command by itself. JavaScript-statements are (almost always) terminated by a semicolon.
206 |
207 | This is a complete statement:
208 |
209 | ```js
210 | let s = "HackYourFuture";
211 | ```
212 |
213 | It is a full command: declare a variable `s` and initialize it with `"HackYourFuture"`. JavaScript doesn't need any other information to know what we want. The statement is terminated with a semicolon.
214 |
215 | However, this is not a complete statement:
216 |
217 | ```js
218 | 4 + 5
219 | ```
220 |
221 | This equals `9`, but what is JavaScript to do with it? It doesn't provide a command. You'd need to do something with it, e.g. `let x = 4 + 5;` or `callFunction(4 + 5)`. We call these parts of statements "expressions". Expressions are not terminated by semicolons. Expressions always "evaluate into a value". In our example, the expression `4 + 5` "evaluates into `9`". If expressions cannot be evaluated into a value, they are invalid. For instance, `4 +` is not a valid expression, it is incomplete, because we need something else after the plus sign.
222 |
223 | So, statements can *contain* expressions. Can expressions contain statements? No, they cannot. However, they can themselves contain expressions. Think about `4 + 5`: it contains the expressions `4` and `5`, as these both evaluate into a value: the expression `4` evaluates into the number `4`, it is a very simple expression. Similarly, `true`, `null`, `undefined` are all expressions.
224 |
225 | ### Examples of expressions
226 |
227 | Here are some examples of expressions. Remember: expressions evaluate into a value, but do not provide a command:
228 |
229 | * `sum(a, b)`
230 | * `a`
231 | * `a > 4 ? "yes" : "no"`
232 | * `a + b`
233 | * `a && b || c`
234 | * `arr.length`
235 | * `obj["name"]`
236 | * `[1, 2, 3]`
237 | * `arr[1]`
238 | * `[1]` (this is an array with one element!)
239 | * `function a() { return 4; }`
240 |
241 | The last one requires a bit of explanation. If you write:
242 |
243 | ```js
244 | function a() { return 4; }
245 | ```
246 |
247 | by itself, this is a *statement* (a function declaration statement). However, if you write it as part of a statement, such as:
248 |
249 | ```js
250 | let b = function a() { return 4; }
251 | ```
252 |
253 | now it is an expression. This is an exceptional situation where something can be a statement or an expression.
254 |
255 | ### Examples of not-expressions
256 |
257 | The following are not expressions:
258 |
259 | * `let` -> this is a keyword, see below
260 | * `let x;` -> this is a statement
261 | * `+` -> this is only an operator
262 | * `if (a > 4) { return "yes"; } else { return "no"; }`
263 |
264 | `if` is also a statement. However, it is quite a complex statement. It is also referred to as a "construct", just like `for`, `while`, `try`, etc.
265 |
266 | ### Keywords
267 |
268 | Some words in JavaScript are special, e.g. `var`, `if`, `while`, `return`. These are called "keywords". You typically cannot use these words as names for your variables, functions.
--------------------------------------------------------------------------------
/fundamentals/XMLHttpRequest.md:
--------------------------------------------------------------------------------
1 | # XMLHttpRequest
2 |
3 | **XMLHttpRequest** is an object to interact with servers. You can retrieve data from a URL without having to do a full page refresh. XMLHttpRequest is used heavily in Ajax programming - [MDN](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest).
4 |
5 | So what is Ajax?
6 |
7 | **Ajax** is a method of exchanging data with a server, and updating parts of a web page without reloading the entire page.
8 |
9 | Let's dive into the code:
10 |
11 | First, we need to make an instance from 'XMLHttpRequest' object.
12 |
13 | ```js
14 | let http = new XMLHttpRequest();
15 | ```
16 |
17 | When we are doing a request it goes through 5 states:
18 |
19 | | Value | Description |
20 | | :---: | --------------------------- |
21 | | 0 | request is not initialized. |
22 | | 1 | request has been set up. |
23 | | 2 | request has been sent. |
24 | | 3 | request is in process. |
25 | | 4 | request is complete. |
26 |
27 | In the code below we are checking if the request is complete or not, and we check the status === 200 just to make sure that we do not get a 404 error - Read more about it here: [HTTP Status Code](https://httpstatuses.com).
28 |
29 | ```js
30 | http.onreadystatechange = function() {
31 | if (http.readyState === 4 && http.status === 200) {
32 | console.log('Response from the server: ' + http.response);
33 | }
34 | };
35 | ```
36 |
37 | There are methods to deal with a server like (GET, POST, UPDATE, DELETE…)
38 |
39 | | Method | Description |
40 | | -------- | ---------------------------- |
41 | | `GET` | retrieve data from server. |
42 | | `POST` | send data to server. |
43 | | `UPDATE` | update data on the server. |
44 | | `DELETE` | delete data from the server. |
45 |
46 | To initialize a request we use [open](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/open) method. The syntax is:
47 |
48 | ```js
49 | XMLHttpRequest.open(method, url, async, user, password);
50 | ```
51 |
52 | The parameters _method_ and _url_ are mandatory, _user_ and _password_ are optional. True is a default value for _async_.
53 |
54 | ```js
55 | http.open('GET', URL, true / false);
56 | ```
57 |
58 | At the end we have to send our request to the server through [send](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/send) method. In our situation we are retrieving a data from the server, so we do not have to pass a parameter to the send request.
59 |
60 | ```js
61 | http.send();
62 | ```
63 |
--------------------------------------------------------------------------------
/fundamentals/array_manipulation.md:
--------------------------------------------------------------------------------
1 | # Array Manipulations
2 |
3 | [MDN on Arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
4 | As we know by now, arrays are collections of values.
5 |
6 | As we will see, there are often many ways to achieve the same thing when working arrays. Over time, you will add different techniques to your mental toolbox to achieve the result you want quickly.
7 |
8 | The basics.
9 |
10 | - How do we create an array?
11 | - How do we add items to an array?
12 | - How do we change items of an array?
13 | - How do we remove items from an array?
14 | - How do we know the length of an array?
15 | - How do we iterate over an array?
16 |
17 | ## How do we create an array?
18 |
19 | An array can be created multiple ways
20 |
21 | From scratch:
22 |
23 | ```js
24 | const a = []; // result: []
25 | const b = ['item1', 'item2']; // result: ['item1', 'item2']
26 |
27 | // The examples with new Array() are NOT recommended and shown here for demo purposes only.
28 | const c = new Array(); // result: []
29 | const d = new Array('item 1', 'item2'); // result: ['item1', 'item2']
30 | const e = new Array(20); // result: [ <20 empty items> ]
31 | const f = new Array(20, 21); // result: [20, 21]
32 | // Note that `e` and `f` are a beautiful example of how weird and unexpected JavaScript can be.
33 | // You should use `a` or `b` by default.
34 | ```
35 |
36 | From value (as an example, many ways to create an array from another value):
37 |
38 | ```js
39 | const a = 'hello world'; // result: 'hello world'
40 | const b = a.split(' '); // result: ['hello', 'world' ]
41 | ```
42 |
43 | ## Array length
44 |
45 | Every array has as a 'static' property `length`. Meaning that we can easily get the amount of items in an array.
46 |
47 | ```js
48 | const f = ['hi', 'there'];
49 | console.log(f.length); // 2
50 | ```
51 |
52 | ## Array index
53 |
54 | We can access array elements through the position of the element in the array. This is called an index. Indices (plural of index) are 0-based, meaning that the first item's index is 0, the second element is 1.
55 |
56 | ```js
57 | const x = ['first', 'second', 'third'];
58 | console.log(x[0]); // 'first'
59 |
60 | x[3] = 'fourth';
61 | ```
62 |
63 | Note that arrays can have empty values. This should be avoided usually to prevent unexpected behaviour.
64 |
65 | ```js
66 | x[10] = 'eleventh';
67 | console.log(x); // [ 'first', 'second', 'third', 'fourth', <6 empty items>, 'eleventh' ]
68 | ```
69 |
70 | Next to the index, we have a wide range of tools to manipulate arrays.
71 |
72 | ## Array methods
73 |
74 | These methods are essential.
75 |
76 | **Extremely important is to remember to always ask these two questions**:
77 |
78 | - What is the return value of this method?
79 | - What does this method do to the original array it is used on?
80 |
81 | **Adding items**
82 |
83 | - [`.push()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) Add item to end of array.
84 | Example:
85 |
86 | ```js
87 | const animals = ['pigs', 'goats', 'sheep'];
88 |
89 | // 1.What is the return value of this method?
90 | // returns the length of the new array
91 | console.log(animals.push('cows'));
92 | // expected output: 4
93 |
94 | // 2. What does this method do to the original array it is used on?
95 | // modifies the original array - adds at the end of the array the given element(s)
96 | console.log(animals);
97 | // expected output: Array ["pigs", "goats", "sheep", "cows"]
98 |
99 | // can add multiple elements in one call
100 | animals.push('chickens', 'parrot');
101 |
102 | console.log(animals);
103 | // expected output: Array ["pigs", "goats", "sheep", "cows", "chicken", "parrot"]
104 | ```
105 |
106 | > _See this in action in this [JSBin](https://jsbin.com/lawovip/edit?js,console)._
107 |
108 | - [`.unshift()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/unshift) Add item to beginning of array.
109 | Example:
110 |
111 | ```js
112 | const array1 = [1, 2, 3];
113 |
114 | // 1.What is the return value of this method?
115 | // returns the length of the new array
116 | console.log(array1.unshift(4, 5));
117 | // expected output: 5
118 |
119 | // 2. What does this method do to the original array it is use
120 | // modifies the original array - adds at the begining of the array the given element(s)
121 | console.log(array1);
122 | // expected output: Array [4, 5, 1, 2, 3]
123 | ```
124 |
125 | > _See this in action in this [JSBin](https://jsbin.com/pikupol/edit?js,console)._
126 |
127 | **Removing items**
128 |
129 | - [`.shift()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/push) Remove first element from array.
130 | Example:
131 |
132 | ```js
133 | const array1 = [1, 2, 3];
134 |
135 | const firstElement = array1.shift();
136 |
137 | // 1.What is the return value of this method?
138 | // returns the first element of the array
139 | console.log(firstElement);
140 | // expected output: 1
141 |
142 | // 2. What does this method do to the original array it is use
143 | // modifies the initial array - removes the first element
144 | console.log(array1);
145 | // expected output: Array [2, 3]
146 | ```
147 |
148 | > _See this in action in this [JSBin](https://jsbin.com/madaxuq/edit?js,console)._
149 |
150 | - [`.pop()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/pop) Remove last element from array. Example:
151 |
152 | ```js
153 | const plants = ['broccoli', 'cauliflower', 'cabbage', 'kale', 'tomato'];
154 |
155 | // 1.What is the return value of this method?
156 | // returns the last element
157 | console.log(plants.pop());
158 | // expected output: "tomato"
159 |
160 | // 2. What does this method do to the original array it is use
161 | // modifies the original array - removes the last element from the end of the array
162 | console.log(plants);
163 | // expected output: Array ["broccoli", "cauliflower", "cabbage", "kale"]
164 |
165 | plants.pop();
166 |
167 | console.log(plants);
168 | // expected output: Array ["broccoli", "cauliflower", "cabbage"]
169 | ```
170 |
171 | > _See this in action in this [JSBin](https://jsbin.com/nicazaf/edit?js,console)._
172 |
173 | - [`.splice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice) Remove a specific element from array using index.
174 | Example:
175 |
176 | ```js
177 | const months = ['Jan', 'March', 'April', 'June'];
178 |
179 | // 1.What is the return value of this method?
180 | // return an array containing the elements removed
181 | console.log(months.splice(1, 0, 'Feb'));
182 |
183 | // 2. What does this method do to the original array it is use
184 | // modifies the original array:
185 |
186 | // inserts at 1st index position
187 | console.log(months);
188 | // expected output: Array ['Jan', 'Feb', 'March', 'April', 'June']
189 |
190 | console.log(months.splice(4, 1, 'May'));
191 | // replaces 1 element at 4th index
192 | console.log(months);
193 | // expected output: Array ['Jan', 'Feb', 'March', 'April', 'May']
194 | ```
195 |
196 | > _See this in action in this [JSBin](https://jsbin.com/yuriyer/edit?js,console)._
197 |
198 | **Useful iterators over arrays**
199 |
200 | - [`.map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) creates a new array with the results of calling a provided function on every element in the calling array.
201 | - [`.filter()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) creates a new array with all elements that pass the test implemented by the provided function.
202 | - [`.sort()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) sorts the elements of an array in place and returns the array
203 |
204 | Detailed examples: [`here`](https://github.com/HackYourFuture/fundamentals/blob/master/fundamentals/map_filter.md)
205 |
--------------------------------------------------------------------------------
/fundamentals/assets/box.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/box.png
--------------------------------------------------------------------------------
/fundamentals/assets/call-stack.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/call-stack.png
--------------------------------------------------------------------------------
/fundamentals/assets/do-while.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/do-while.png
--------------------------------------------------------------------------------
/fundamentals/assets/event-loop-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/event-loop-1.png
--------------------------------------------------------------------------------
/fundamentals/assets/event-loop-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/event-loop-2.png
--------------------------------------------------------------------------------
/fundamentals/assets/event-loop-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/event-loop-3.png
--------------------------------------------------------------------------------
/fundamentals/assets/event-loop-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/event-loop-4.png
--------------------------------------------------------------------------------
/fundamentals/assets/event-loop-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/event-loop-5.png
--------------------------------------------------------------------------------
/fundamentals/assets/express.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/express.png
--------------------------------------------------------------------------------
/fundamentals/assets/map-filter-reduce-emoji.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/map-filter-reduce-emoji.png
--------------------------------------------------------------------------------
/fundamentals/assets/prototype.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/prototype.png
--------------------------------------------------------------------------------
/fundamentals/assets/prototypes-fundamental.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/prototypes-fundamental.png
--------------------------------------------------------------------------------
/fundamentals/assets/reduce-bucket.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/reduce-bucket.png
--------------------------------------------------------------------------------
/fundamentals/assets/scopes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/scopes.png
--------------------------------------------------------------------------------
/fundamentals/assets/sync-async.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HackYourFuture/fundamentals/b88b8bdd7f7dfb28b2c0845015eb6c09029c61dc/fundamentals/assets/sync-async.png
--------------------------------------------------------------------------------
/fundamentals/async_await.md:
--------------------------------------------------------------------------------
1 | # async & await
2 |
3 | ## Revisiting promises
4 |
5 | The example shown in Listing 1 below was used in the fundamental about [promises](./promises.md) to illustrate the chaining of promises with a final `.catch()` at the end of the chain to handle errors.
6 |
7 | ```js
8 | function fetchAndRender(url, otherUrl) {
9 | fetchJSON(url)
10 | .then(data => {
11 | renderData(data);
12 | return fetchJSON(otherUrl);
13 | })
14 | .then(otherData => {
15 | renderOtherData(otherData);
16 | })
17 | .catch(err => {
18 | renderError(err);
19 | });
20 | }
21 | ```
22 |
23 | Listing 1. Chained promises.
24 |
25 | In this example the `fetchJSON()` function fetches data from a remote API and returns a promise. When the promise returned by the first call to `fetchJSON()` resolves, the returned data is rendered to the DOM by means of the `renderData()` function. Subsequently, a second call is made to `fetchJSON` to fetch other data. When the promise of that second call is fulfilled, the supplemental data is rendered to the DOM.
26 |
27 | Because there is a time delay between the arrival of the first data set and the arrival of the second data set, a user looking at the web page will see the page being filled up in two separate updates. It may be a better user experience if the page updates are all done in one go. We could modify the code of Listing 1 to postpone rendering the first data set until the second data set (`otherData`) is received. This is illustrated in Figure 2.
28 |
29 | ```js
30 | function fetchAndRender(url, otherUrl) {
31 | fetchJSON(url)
32 | .then(data => {
33 | return fetchJSON(otherUrl)
34 | .then(otherData => {
35 | renderData(data);
36 | renderOtherData(otherData);
37 | });
38 | })
39 | .catch(err => {
40 | renderError(err);
41 | });
42 | }
43 | ```
44 |
45 | Listing 2. Nested promises.
46 |
47 | Now, when the promise returned by the second call to `fetchJSON()` is fulfilled, the `.then()` method directly called on that second promise is used to render both the data from the first `fetchJSON()` call (still accessible through a _closure_) and the `otherData` from the second promise.
48 |
49 | We must still return the result of the inner promise chain to ensure that any promise rejection in that inner chain is caught by the terminating `.catch()` of the outer chain. That result will in this example be a promise that is fulfilled to the value `undefined` or a rejected promise in case of an error.
50 |
51 | To achieve the goal from this example of rendering in one go, there is yet another option available to us using promises, provided that the second call to `fetchJSON()` is not dependent on data from the first call. In this example this is indeed the case. This makes it possible to use the `Promise.all()` method, as shown in Listing 3.
52 |
53 | ```js
54 | function fetchAndRender(url, otherUrl) {
55 | Promise.all([fetchJSON(url), fetchJSON(otherUrl)])
56 | .then(([data, otherData]) => {
57 | renderData(data);
58 | renderOtherData(otherData);
59 | })
60 | .catch(err => {
61 | renderError(err);
62 | });
63 | }
64 | ```
65 |
66 | Listing 3. Running promises in parallel using Promise.all().
67 |
68 | The promises from the two calls to `fetchJSON()` now run in parallel. `Promise.all()` returns a new promise that is resolved if all the promises passed in the array argument are resolved or is rejected as soon as any one of the promises is rejected. Its fulfilled value is an array of the fulfilled values of the individual promises, in the same order. Because the promises run in parallel the browser can send out two simultaneous XMLHttpRequests, thereby improving overall performance.
69 |
70 |
71 | ### The async/await alternative
72 |
73 | The keywords `async` and `await` were introduced in ECMAScript 2017 as a new way to 'consume' promises. It obviates the need to use `.then()` and `.catch()` and makes it possible to write code that uses promises in a "synchronous" fashion.
74 |
75 | Referring back to the code snippet of Listing 1, we can now rewrite this code as shown in Listing 4 below:
76 |
77 | ```js
78 | async function fetchAndRender(url, otherUrl) {
79 | try {
80 | const data = await fetchJSON(url);
81 | renderData(data);
82 | const otherData = await fetchJSON(otherUrl);
83 | renderOtherData(otherData);
84 | }
85 | catch (err) {
86 | renderError(err);
87 | }
88 | }
89 | ```
90 |
91 | Listing 4. Reimplementation of Listing 1 using async/await
92 |
93 | The `await` keyword causes the code execution to be suspended in a non-blocking manner until the promise returned by `fetchJSON()` is resolved. Once the promise is resolved the awaited expression returns the fulfilled value of the promise and execution resumes at the point where it was left off.
94 |
95 | > If you forget to use the `await` keyword you will get the promise itself rather than its fulfilled value. And of course, there will be no 'waiting'.
96 |
97 | You can only use the `await` keyword in functions marked with the keyword `async`. The return value (if any) of that function is also a promise.
98 |
99 | Note that you must use a `try`-`catch` block to deal with errors. Please refer to the [try...catch](./try_catch.md) fundamental for more information.
100 |
101 | Referring back to the nested promises of Listing 2, we can now with `async`/`await` achieve our objective of rendering in one go simply by moving the call to `renderData()` after the second `fetchJSON()` call, as shown in Listing 5. What can be easier than that?
102 |
103 | ```js
104 | async function fetchAndRender(url, otherUrl) {
105 | try {
106 | const data = await fetchJSON(url);
107 | const otherData = await fetchJSON(otherUrl);
108 | renderData(data);
109 | renderOtherData(otherData);
110 | }
111 | catch (err) {
112 | renderError(err);
113 | }
114 | }
115 | ```
116 |
117 | Listing 5. Reimplementation of Listing 2 using async/await
118 |
119 | With `async`/`await` we can also take advantage of running promises in parallel. In this case we must use the same `Promise.all()` method as shown in Listing 3. The version with `async`/`await` is shown in Listing 6 below.
120 |
121 | ```js
122 | async function fetchAndRender(url, otherUrl) {
123 | try {
124 | const [data, otherData] = await Promise.all([fetchJSON(url), fetchJSON(otherUrl)]);
125 | renderData(data);
126 | renderOtherData(otherData);
127 | }
128 | catch (err) {
129 | renderError(err);
130 | }
131 | }
132 | ```
133 |
134 | Listing 6. Reimplementation of Listing 3 using async/await
135 |
136 | More info on MDN:
137 |
138 | - [async function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function)
139 | - [await](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await)
140 |
141 | Wes Bos video on `async`/`await`: https://youtu.be/9YkUCxvaLEk
142 |
143 |
--------------------------------------------------------------------------------
/fundamentals/bug-challenge-es6/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-1"],
3 | "compact": true
4 | }
--------------------------------------------------------------------------------
/fundamentals/bug-challenge-es6/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/fundamentals/bug-challenge-es6/__tests__/bug-challenge-tests.js:
--------------------------------------------------------------------------------
1 | import BugChallenge from '../bug-challenge';
2 | import '../jest-helpers';
3 |
4 | describe('Bug challenge ES6', () => {
5 |
6 | let challenge;
7 | beforeEach(() => {
8 | console.clear();
9 | challenge = new BugChallenge();
10 | });
11 |
12 | describe('bug1', () => {
13 |
14 | it("should list the names and ages of people", () => {
15 | challenge.bug1();
16 |
17 | expect(console.logs).toEqual([
18 | "Alice is 25",
19 | "Bob is 27",
20 | "Charlie is 40"
21 | ]);
22 | });
23 |
24 | });
25 |
26 | describe('bug2', () => {
27 |
28 | it("should list all items in the array in reverse order", () => {
29 | challenge.bug2();
30 |
31 | expect(console.logs).toEqual([
32 | '4',
33 | '3',
34 | '2',
35 | '1'
36 | ]);
37 | });
38 |
39 | });
40 |
41 | describe('bug3', () => {
42 |
43 | it("should output the total of the indices (0 + 1 + 2 = 3)", () => {
44 | challenge.bug3();
45 |
46 | expect(console.logs).toEqual([
47 | '3'
48 | ]);
49 | });
50 |
51 | });
52 |
53 | describe('bug4', () => {
54 |
55 | it("should list all movies and actors, except the top 3", () => {
56 | challenge.bug4();
57 |
58 | expect(console.logs).toEqual([
59 | 'movie: Pulp Fiction',
60 | 'movie: Fight club',
61 | 'movie: Forrest Gump',
62 | 'movie: Inception',
63 | 'movie: Goodfellas',
64 | 'movie: The Matrix',
65 | 'movie: Interstellar',
66 | 'actor: Al Pacino',
67 | 'actor: Daniel Day-Lewis',
68 | 'actor: Duston Hoffman',
69 | 'actor: Tom Hanks',
70 | 'actor: Anthony Hopkins',
71 | 'actor: Paul Newman',
72 | 'actor: Denzel Washington'
73 | ]);
74 | });
75 |
76 | });
77 |
78 | describe('bug5', () => {
79 |
80 | it("should fetch with caching disabled", () => {
81 | challenge.bug5();
82 |
83 | expect(console.logs).toEqual([
84 | 'fetch: GET http://www.example.com (useCaching=false)'
85 | ]);
86 | });
87 |
88 | });
89 |
90 | describe('bug6', () => {
91 |
92 | it("should run main.js", () => {
93 | challenge.bug6();
94 |
95 | expect(console.logs).toEqual([
96 | 'run: script=main.js'
97 | ]);
98 | });
99 |
100 | });
101 |
102 | describe('bug7', () => {
103 |
104 | it("should first run with stopOnError=all and then with stopOnError=null", () => {
105 | challenge.bug7();
106 |
107 | expect(console.logs).toEqual([
108 | 'run: stopOnError=all',
109 | 'run: stopOnError=null'
110 | ]);
111 | });
112 |
113 | });
114 |
115 |
116 | describe('bug8', () => {
117 |
118 | it("should lists numbers 1 through 6", () => {
119 | challenge.bug8();
120 | jest.runAllTimers();
121 |
122 | expect(console.logs).toEqual([
123 | '1',
124 | '2',
125 | '3',
126 | '4',
127 | '5'
128 | ]);
129 | });
130 |
131 | });
132 |
133 | describe('bug9', () => {
134 |
135 | it("should list only BMWs", () => {
136 | challenge.bug9();
137 |
138 | expect(console.logs).toEqual([
139 | 'BMW i8',
140 | 'BMW M3'
141 | ]);
142 | });
143 |
144 | });
145 |
146 | describe('bug10', () => {
147 |
148 | it("should print 'Help'", () => {
149 | challenge.bug10();
150 |
151 | expect(console.logs).toEqual([
152 | 'Help'
153 | ]);
154 | });
155 |
156 | });
157 |
158 | describe('bug11', () => {
159 |
160 | it("should correctly add players Alice & Bob", () => {
161 | challenge.bug11();
162 |
163 | expect(console.logs).toEqual([
164 | 'Player Alice has 0 points',
165 | 'Player Bob has 0 points'
166 | ]);
167 | });
168 |
169 | });
170 |
171 | describe('bug12', () => {
172 |
173 | it("should not change the value of the outer y", () => {
174 | challenge.bug12();
175 |
176 | expect(console.logs).toEqual([
177 | 'Printing vector at (6, 7)',
178 | 'y=5'
179 | ]);
180 | });
181 |
182 | });
183 | describe('bug13', () => {
184 | it("should return that AI, Godfather and Inception are in the top10 movie list", () => {
185 | challenge.bug13();
186 | jest.runAllTimers();
187 |
188 | expect(console.logs).toEqual([
189 | "Independence Day is not in the top 10!",
190 | "AI is in the top 10!",
191 | "Godfather is in the top 10!",
192 | "Inception is in the top 10!"
193 | ]);
194 | });
195 |
196 | });
197 | describe('bug14', () => {
198 | it("should return that AI is best movie ever", () => {
199 | challenge.bug14();
200 | jest.runAllTimers();
201 |
202 | expect(console.logs).toEqual([
203 | "AI is best movie ever",
204 | "Godfather is not best movie ever",
205 | ]);
206 | });
207 | });
208 | describe('bug15', () => {
209 | it("should return Al Pacino as first actor after sorting alphabetically", () => {
210 | challenge.bug15();
211 | jest.runAllTimers();
212 |
213 | expect(console.logs).toEqual([
214 | 'The first actor when sorted alphabetically is Al Pacino'
215 | ]);
216 | });
217 | });
218 | describe('bug16', () => {
219 | it("should return that Al Pacino is ranked 4th among all actors", () => {
220 | challenge.bug16();
221 | jest.runAllTimers();
222 |
223 | expect(console.logs).toEqual([
224 | 'Al Pacino is ranked 4'
225 | ]);
226 | });
227 | });
228 | });
229 |
--------------------------------------------------------------------------------
/fundamentals/bug-challenge-es6/bug-challenge.js:
--------------------------------------------------------------------------------
1 | export default class BugChallenge {
2 | //Do NOT change the top10Movies and top10Actors variables to fix your tests
3 | //believe me: the problem is in bug() functions, not in these arrays ;)
4 | top10Movies = [
5 | 'AI',
6 | 'Shawshank Redemption',
7 | 'Godfather',
8 | 'Pulp Fiction',
9 | 'Fight club',
10 | 'Forrest Gump',
11 | 'Inception',
12 | 'Goodfellas',
13 | 'The Matrix',
14 | 'Interstellar'
15 | ]
16 | top10Actors = [
17 | 'Marlon Brando',
18 | 'Jack Nickolson',
19 | 'Robert De Niro',
20 | 'Al Pacino',
21 | 'Daniel Day-Lewis',
22 | 'Duston Hoffman',
23 | 'Tom Hanks',
24 | 'Anthony Hopkins',
25 | 'Paul Newman',
26 | 'Denzel Washington'
27 |
28 | ]
29 | //------
30 | // Bugs
31 |
32 | bug1() {
33 | const people = [{
34 | name: 'Alice',
35 | age: 25
36 | }, {
37 | name: 'Bob',
38 | age: 27
39 | }, {
40 | name: 'Charlie',
41 | age: 40
42 | }];
43 |
44 | for (let person in people) {
45 | console.log(`${person.name} is ${person.age}`);
46 | }
47 | }
48 |
49 | bug2() {
50 | const array = [1, 2, 3, 4];
51 |
52 | for (let i = 0; i < array.length; i++) {
53 | console.log(array.pop());
54 | }
55 | }
56 |
57 | bug3() {
58 | const array = {};
59 | array[0] = 'a';
60 | array[1] = 'b';
61 | array[2] = 'c';
62 |
63 | let total = 0;
64 | for (let key in obj) {
65 | total += key;
66 | }
67 |
68 | console.log(total);
69 | }
70 |
71 | bug4() {
72 | // We list all movies, except the top 3.
73 | let index = 3;
74 | for (index; index < this.top10Movies.length; index++) {
75 | console.log(`movie: ${this.top10Movies[index]}`);
76 | }
77 |
78 | // We also list all actors, except the top 3.
79 | for (index; index < top10Actors.length; index++) {
80 | console.log(`actor: ${this.top10Actors[index]}`);
81 | }
82 | }
83 |
84 | bug5() {
85 | const defaultMethod = 'GET';
86 | const defaultUseCaching = true;
87 |
88 | function fetch(options) {
89 | const url = options.url;
90 | const method = options.method || defaultMethod;
91 | const useCaching = options.useCaching || defaultUseCaching;
92 |
93 | console.log(`fetch: ${method} ${url} (useCaching=${useCaching})`);
94 | }
95 |
96 | fetch({
97 | url: 'http://www.example.com',
98 | useCaching: false
99 | });
100 | }
101 |
102 | bug6() {
103 | function run(options) {
104 | if (options.script == undefined) {
105 | options.script = 'main.js';
106 | }
107 |
108 | console.log(`run: script=${options.script}`);
109 | }
110 |
111 | run();
112 | }
113 |
114 | bug7() {
115 | function run(options = {}) {
116 | if (options.stopOnError == undefined) {
117 | options.stopOnError = 'all';
118 | }
119 |
120 | console.log(`run: stopOnError=${options.stopOnError}`);
121 | }
122 |
123 | run();
124 | run({stopOnError: null});
125 | }
126 |
127 | bug8() {
128 | for (let i = 0; i < 5; i++) {
129 | setTimeout(function () {
130 | console.log(i+1);
131 | }, 100*i);
132 | }
133 | }
134 |
135 | bug9() {
136 | const cars = [{
137 | make: 'Volvo',
138 | type: 'S90'
139 | }, {
140 | make: 'BMW',
141 | type: 'i8'
142 | }, {
143 | make: 'BMW',
144 | type: 'M3'
145 | }, {
146 | make: 'Audi',
147 | type: 'A6'
148 | }];
149 |
150 | function findCars(make) {
151 | return cars.filter(car => car.make = make);
152 | }
153 |
154 | for (let bmw of findCars('BMW')) {
155 | console.log(`${bmw.make} ${bmw.type}`);
156 | }
157 | }
158 |
159 | bug10() {
160 | const command = 'printHelp';
161 |
162 | switch (command) {
163 | case 'printMath':
164 | console.log(`√9=${Math.sqrt(9)}`);
165 | case 'printHelp':
166 | console.log('Help');
167 | case 'quit':
168 | console.log('Quitting');
169 | }
170 | }
171 |
172 | bug11() {
173 | class Game {
174 | constructor() {
175 | this.players = [];
176 | }
177 |
178 | addPlayers(names) {
179 | names.forEach(function (name) {
180 | this.players.push({name, points: 0});
181 | });
182 | }
183 | }
184 |
185 | const game = new Game();
186 | game.addPlayers(['Alice', 'Bob']);
187 |
188 | for (let player of game.players) {
189 | console.log(`Player ${player.name} has ${player.points} points`);
190 | }
191 | }
192 |
193 | bug12() {
194 | let y = 5;
195 |
196 | function printVector() {
197 | let x = 6;
198 | y = 7;
199 |
200 | console.log(`Printing vector at (${x}, ${y})`);
201 | }
202 |
203 | printVector();
204 | console.log(`y=${y}`);
205 | }
206 |
207 | bug13() {
208 | let notInTop10 = (movieName) => {
209 | return !this.top10Movies.indexOf(movieName)
210 | }
211 | console.log('Independence Day is ' + (notInTop10('Independence Day')?'not ':'') + 'in the top 10!');
212 | console.log('AI is ' + (notInTop10('AI')?'not ':'') + 'in the top 10!');
213 | console.log('Godfather is ' + (notInTop10('Godfather')?'not ':'') + 'in the top 10!');
214 | console.log('Inception is ' + (notInTop10('Inception')?'not ':'') + 'in the top 10!');
215 | }
216 | bug14() {
217 |
218 | console.log('AI is ' + (isInFirstPlace('AI')?'':'not ') + 'best movie ever')
219 | console.log('Godfather is ' + (isInFirstPlace('Godfather')?'':'not ') + 'best movie ever')
220 | let isInFirstPlace = (movieName) => {
221 | return this.top10Movies[0] === movieName
222 | }
223 | }
224 | bug15() {
225 | let getAlphabeticalFirst = function() {
226 | return this.top10Actors.sort()[0]
227 | }
228 |
229 | console.log(`The first actor when sorted alphabetically is ${getAlphabeticalFirst()}`)
230 | }
231 | bug16() {
232 | const ranking = this.top10Actors.indexOf('Al Pacino');
233 | // let thirdRankedActor = this.top10Actors['2'];
234 | console.log(`Al Pacino is ranked ${ranking + '1'}`)
235 | }
236 |
237 | }
238 |
--------------------------------------------------------------------------------
/fundamentals/bug-challenge-es6/jest-helpers.js:
--------------------------------------------------------------------------------
1 | jest.useFakeTimers();
2 |
3 | console.logs = [];
4 |
5 | console.clear = function() {
6 | console.logs = [];
7 | }
8 | console.log = function(message) {
9 | console.logs.push(message.toString());
10 | }
11 |
--------------------------------------------------------------------------------
/fundamentals/bug-challenge-es6/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bug-challenge-es6",
3 | "jest": {
4 | "automock": false,
5 | "testPathIgnorePatterns": [
6 | "/node_modules/"
7 | ]
8 | },
9 | "scripts":{
10 | "test": "jest"
11 | },
12 | "devDependencies": {
13 | "babel-core": "^6.18.2",
14 | "babel-jest": "^17.0.2",
15 | "babel-preset-es2015": "^6.18.0",
16 | "babel-preset-stage-1": "^6.16.0",
17 | "jest": "^17.0.3",
18 | "jest-cli": "^17.0.3"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/fundamentals/code_commenting.md:
--------------------------------------------------------------------------------
1 | # Code Commenting
2 |
3 | First the straightforward part: how do we place comments in our code?
4 |
5 | ## JavaScript
6 | Single line comments
7 | ```js
8 | // Change heading:
9 | document.getElementById("myH").innerHTML = "My First Page";
10 | ```
11 |
12 | Single line comments at end of the line:
13 | ```js
14 | const x = 5; // Declare x, give it the value of 5
15 | ```
16 |
17 | Coding **well** in JavaScript: [JSDoc](https://jsdoc.app/)
18 |
19 | ## HTML
20 | [W3Schools](https://www.w3schools.com/html/html_comments.asp)
21 | Comments
22 | ```html
23 |
25 |
26 |
27 | ```
28 |
29 |
30 | ## CSS
31 | [MDN on CSS comments](https://developer.mozilla.org/en-US/docs/Web/CSS/Comments)
32 | ```css
33 | /* Comment */
34 |
35 | /*
36 | A comment
37 | which stretches
38 | over several
39 | lines
40 | */
41 | ```
42 |
43 | ## When to comment?
44 | Now for the hard part: when to comment? When you work for different companies, you will see different styles. Embrace something you like, and then learn to let go. Google on "when to comment code?" and you'll find a big bunch of different opinions.
45 |
46 | The general concept is, however, that it is there to help make the code more easy to understand. Note, however, that comments can also make code more difficult to understand when not applied properly.
47 |
--------------------------------------------------------------------------------
/fundamentals/code_formatting.md:
--------------------------------------------------------------------------------
1 | # Code Formatting
2 |
3 | When you write your JavaScript code you need to take into account two types of consumer:
4 |
5 | 1. Human readers (you yourself, your co-workers, classmates, you yourself in a year's time from now, etc.).
6 | 2. The JavaScript engine.
7 |
8 | Starting with the latter, the JavaScript engine does not care about code formatting at all and is perfectly happy to work with one-letter variable names. 'Minification' is a process that is sometimes used to reduce the size of JavaScript files hosted on a web server so that they take less time to transfer over a network to a web browser. The code below show some 'minified' code.
9 |
10 | ```js
11 | const o=[6,3,10,1].reduce((o,c)=>(o.push(c*c),o),[]);console.log(o);
12 | ```
13 |
14 | Clearly, the above code is incomprehensible to humans. The original code is shown below, nicely formatted for the benefit of human readers.
15 |
16 | ```js
17 | const arr = [6, 3, 10, 1];
18 | const squares = arr.reduce((acc, elem) => {
19 | acc.push(elem * elem);
20 | return acc;
21 | }, []);
22 | console.log(squares); // -> [36, 9, 100, 1]
23 | ```
24 |
25 | In comparison with the minified code, the original code makes use of new lines and indentation to show structure and uses meaningful variable names, solely for the benefit of the human reader.
26 |
27 | Over time, a standard way of formatting JavaScript code has emerged (actually this standard is fairly common across all languages that are derived from the C-language, including JavaScript but also C++, Java and C#).
28 |
29 | In the next sections we will discuss the most important code formatting conventions for JavaScript. At the end of this document you will find some code that is formatted according to these rules.
30 |
31 | ## Blank lines
32 |
33 | Use a single blank line to separate blocks of related code. This is similar to separating paragraphs with a blank line in written text.
34 |
35 | ## Curly braces
36 |
37 | Curly braces are used to start and end code blocks, often as part of an `if`, `switch`, `while` or `for` statement. The opening curly brace should be placed at the end of a line. The closing curly brace should be aligned with the beginning of the line that started the code block.
38 |
39 | ```js
40 | if (condition) {
41 | // ...
42 | } else {
43 | // ...
44 | }
45 | ```
46 |
47 | ## Indentation
48 |
49 | Code blocks inside curly braces should be indented by 2 or 4 spaces (choose one or the other, and then stick to it). In case of nested code blocks, for each level of nesting the amount of indentation should be incremented by the standard amount (2 or 4):
50 |
51 | ```js
52 | function myFunction() {
53 | if (condition) {
54 | // ...
55 | } else {
56 | // ...
57 | }
58 | }
59 | ```
60 |
61 | ## Spacing
62 |
63 | - Add a space after keywords, e.g. `if (`, `for (`
64 | - Add a space after a `,` `;` (in a `for` loop) and `:` (e.g. object keys)
65 | - Add a space before and after operators, e.g. `a + b`
66 |
67 | ## Use VSCode for well-formatted JavaScript
68 |
69 | Rather than continuing and specifying every little detail on how to format JavaScript code in a standard format, we can call in the help of VSCode.
70 |
71 | VSCode comes with a built-in code formatter for JavaScript. To format the current document in a standard fashion, press the following key combination:
72 |
73 | | | Windows | Mac | Linux |
74 | | --------- | ------- | ----- | ----- |
75 | | **Format Document** (make it pretty) | Shift‑Alt‑F | ⇧⌥F| Ctrl‑Shift‑I |
76 |
77 | Just make it a habit to bring this three-finger salute just before saving your document or whenever it becomes messy and you're good to go!
78 |
79 | > There are a number of user settings that you can apply in VSCode to enable auto-formatting as you type (or paste). See [VSCode Tips](../VSCodeTips/README.md#customise-vscode-settings) for further details.
80 | >
81 |
82 | ## ESLint
83 |
84 | [ESLint](https://eslint.org/) is a tool that can check your JavaScript code for common errors and bad practices. See [VSCode Tips](../VSCodeTips/README.md#installation-instructions) on how to set it up.
85 |
86 | ESLint is configured via user-definable rules that specify what to check. These rules must be defined in a file called `.eslintrc.json` placed in the root folder of your project repository. For the lectures and homework of the three HYF JavaScript modules it is recommended that you create an `.eslintrc.json` file and copy and paste the content shown below into that file.
87 |
88 | More information about ESLint Rules [here](https://eslint.org/docs/rules/).
89 |
90 | Make sure that you correct any errors and warnings that ESLint produces before considering your JavaScript code done!
91 |
92 | ```json
93 | {
94 | "env": {
95 | "browser": true,
96 | "commonjs": true,
97 | "es6": true,
98 | "node": true
99 | },
100 | "parserOptions": {
101 | "ecmaVersion": 2017,
102 | "ecmaFeatures": {
103 | "jsx": true
104 | },
105 | "sourceType": "module"
106 | },
107 | "extends": [
108 | "eslint:recommended"
109 | ],
110 | "rules": {
111 | "no-const-assign": "warn",
112 | "no-this-before-super": "warn",
113 | "no-undef": "warn",
114 | "no-unreachable": "warn",
115 | "no-unused-vars": "warn",
116 | "constructor-super": "warn",
117 | "valid-typeof": "warn",
118 | "no-var": "warn",
119 | "prefer-const": "warn",
120 | "no-multiple-empty-lines": "warn",
121 | "eol-last": [
122 | "error",
123 | "always"
124 | ],
125 | "no-console": "off",
126 | "camelcase": "warn",
127 | "eqeqeq": [
128 | "error",
129 | "always",
130 | {
131 | "null": "ignore"
132 | }
133 | ],
134 | "semi": [
135 | "warn",
136 | "always"
137 | ]
138 | }
139 | }
140 | ```
141 |
142 |
143 | ## Example of well-formatted code
144 |
145 | (With the help of the VSCode formatter and ESLint.)
146 |
147 | ```js
148 | 'use strict';
149 |
150 | const board = [
151 | ['T', 'T', '.', 'F'],
152 | ['T', '.', '.', '.'],
153 | ['.', '.', '.', '.'],
154 | ['R', '.', '.', 'W']
155 | ];
156 |
157 | const robot = {
158 | x: 0,
159 | y: 0,
160 | dir: 'up',
161 | };
162 |
163 | let flagReached = false;
164 | let moves = 0;
165 |
166 | board.reverse();
167 |
168 | const trailIndicators = {
169 | left: '←',
170 | right: '→',
171 | up: '↑',
172 | down: '↓'
173 | };
174 |
175 | function render() {
176 | console.log('\n ' + moves + ':');
177 | for (let row = board.length - 1; row >= 0; row--) {
178 | const cells = board[row];
179 | let line = '';
180 | for (let col = 0; col < cells.length; col++) {
181 | line += ' ' + cells[col] + ' ';
182 | }
183 | console.log(line);
184 | }
185 | if (flagReached) {
186 | console.log('\nHurray! Flag reached in ' + moves + ' steps!');
187 | }
188 | }
189 |
190 | function move() {
191 | let x = robot.x;
192 | let y = robot.y;
193 |
194 | switch (robot.dir) {
195 | case 'up':
196 | y = y < board.length - 1 ? y + 1 : y;
197 | break;
198 | case 'down':
199 | y = y > 0 ? y - 1 : y;
200 | break;
201 | case 'left':
202 | x = x > 0 ? x - 1 : x;
203 | break;
204 | case 'right':
205 | x = x < board[y].length - 1 ? x + 1 : x;
206 | break;
207 | }
208 |
209 | const cellContents = board[y][x];
210 |
211 | if (cellContents === '.' || cellContents === 'F') {
212 | board[robot.y][robot.x] = trailIndicators[robot.dir];
213 | robot.x = x;
214 | robot.y = y;
215 | board[y][x] = 'R';
216 | if (cellContents === 'F') {
217 | flagReached = true;
218 | }
219 | }
220 |
221 | moves += 1;
222 | render();
223 | }
224 |
225 | function turn(turnDirection) {
226 | if (turnDirection !== 'left' && turnDirection !== 'right') {
227 | console.log('ignoring invalid turn', turnDirection);
228 | }
229 | switch (robot.dir) {
230 | case 'up':
231 | robot.dir = turnDirection === 'left' ? 'left' : 'right';
232 | break;
233 | case 'down':
234 | robot.dir = turnDirection === 'left' ? 'right' : 'left';
235 | break;
236 | case 'left':
237 | robot.dir = turnDirection === 'left' ? 'down' : 'up';
238 | break;
239 | case 'right':
240 | robot.dir = turnDirection === 'left' ? 'up' : 'down';
241 | break;
242 | }
243 | }
244 |
245 | render();
246 |
247 | // start of robot game instructions
248 | move();
249 | turn('right');
250 | move();
251 | move();
252 | move();
253 | turn('left');
254 | move();
255 | move();
256 | // end of robot game instructions
257 | ```
258 |
259 |
--------------------------------------------------------------------------------
/fundamentals/conditional_execution.md:
--------------------------------------------------------------------------------
1 | # Conditional execution
2 |
3 | The normal order of execution of statements in a computer program is in straight-line order, from top to bottom. However, sometimes it is desirable to execute one or more statements _conditionally_, i.e. depending on whether some condition – determined by the state of your program – holds true.
4 |
5 | ## The `if` statement
6 |
7 | In its simplest form the `if` statement looks like this:
8 |
9 | ```js
10 | if (condition) {
11 | // one or more statements that will be executed
12 | // if, and only if the condition holds true
13 | }
14 | ```
15 |
16 | Here, `condition` is a boolean expression that resolves to either `true` or `false` (or, more precisely, any expression that is 'truthy' or 'falsy', as will be explained later).
17 |
18 | The statements within the curly braces `{` and `}` will be executed if the condition holds true, otherwise these statements will be skipped (i.e. ignored).
19 |
20 | An example:
21 |
22 | ```js
23 | if (distance < 10) {
24 | console.log('I will take the bike.');
25 | }
26 | ```
27 |
28 | Here, the condition is the boolean expression `distance > 10`, which is either `true` or `false`.
29 |
30 | It is also possible to add a statement block to be executed if (and only if) the condition does **not** hold true, using an `else` clause.
31 |
32 | ```js
33 | if (distance < 10) {
34 | console.log('I will take the bike.');
35 | } else {
36 | console.log('I will go by car.');
37 | }
38 | ```
39 |
40 | A condition can take more complex forms, using `&&` (logical AND) and `||` (logical OR) operators:
41 |
42 | ```js
43 | if (distance < 10 && !raining) {
44 | console.log('I will take the bike.');
45 | } else {
46 | console.log('I will go by car.');
47 | }
48 | ```
49 |
50 | In the example above `raining` is a boolean variable (either `true` or `false`), and the exclamation mark is the logical NOT operator that negates the boolean value (if it was `true` the result after negation is false and vice versa).
51 |
52 | For more complex decisions you can concatenate multiple conditions using `else if` clauses.
53 |
54 | ```js
55 | if (distance < 1) {
56 | console.log('I will walk.');
57 | } else if (distance < 10) {
58 | console.log('I will take the bike.');
59 | } else if (distance < 50) {
60 | console.log('I will go by car.');
61 | } else {
62 | console.log('I will take the train.');
63 | }
64 | ```
65 |
66 | The statement block inside an `if`, `else` or `else if` may itself contain nested `if` statements, as in this example:
67 |
68 | ```js
69 | if (distance < 10) {
70 | if (raining) {
71 | console.log('I will go public transportation.');
72 | } else {
73 | console.log('I will walk.');
74 | }
75 | } else {
76 | console.log('I will go by car.');
77 | }
78 | ```
79 |
80 | > As (nested) `if` statements can become quite complex it is very important that you indent your source code so that there can be no confusion about which statement blocks are executed for each condition, as was done in the examples.
81 |
82 | >More information on MDN: [if...else](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else)
83 |
84 | ## The conditional (ternary) operator
85 |
86 | This operator can be used as a shortcut for an `if` statement when dealing with expressions.
87 |
88 | The general format is:
89 |
90 | ```js
91 | condition ? expr1 : expr2
92 | ```
93 |
94 | ('ternary' means: _composed of three parts_)
95 |
96 | It is often used in combination with an assignment, as in this example:
97 |
98 | ```js
99 | const conditionOfCar = age < 1 ? 'new' : 'used';
100 | ```
101 |
102 | The `conditionOfCar` variable will be assigned the string `'new'` if the `age < 1` condition holds true, otherwise it is assigned the string `'used'`.
103 |
104 | It is always possible to rewrite a ternary operator as an `if-then-else` statement, for example:
105 |
106 | ```js
107 | let conditionOfCar;
108 | if (age < 1) {
109 | conditionOfCar = 'new';
110 | } else {
111 | conditionOfCar = 'used';
112 | }
113 | ```
114 |
115 | Note that you can't use `const` here for `conditionOfCar` because we can't combine declaration and initialization in a single statement. Therefore we must now use `let`.
116 |
117 | It is **not** recommended to use the conditional operator if you do not intend to use its value:
118 |
119 | ```js
120 | // Don't do this: it's yucky code
121 | age < 1 ? console.log('new') : console.log('used');
122 | ```
123 |
124 | >More information on MDN: [Conditional (ternary) Operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)
125 |
126 | ## The switch statement
127 |
128 | The `switch` statement can sometimes be a useful alternative to a concatenation of `if` statements. This is the case when the condition is an expression that can be decomposed into a number of distinct values or _cases_, as shown in the example below.
129 |
130 | ```js
131 | const hyfModule = 'JavaScript-1';
132 |
133 | switch (hyfModule) {
134 | case 'HTML/CSS':
135 | console.log('In this module you will learn HTML and CSS.');
136 | break;
137 | case 'JavaScript-1':
138 | console.log('In this module you will learn Git and JavaScript basics.');
139 | break;
140 | case 'JavaScript-2':
141 | console.log('In this module you will learn about JavaScript in the browser with HTML and CSS.');
142 | break;
143 | case 'JavaScript-3':
144 | console.log('In this module you will learn about Async and API calls.');
145 | break;
146 | case 'Node':
147 | console.log('This module is about building server and CLI applications using Node.');
148 | break;
149 | case 'Database':
150 | console.log('In this module is about Relational and Non-Relational Data and Database Systems.');
151 | break;
152 | case 'React':
153 | console.log('In this module you will to build Single Page Applications using React.');
154 | break;
155 | case 'Project':
156 | console.log('In this final module you will do your graduation project.');
157 | break;
158 | default:
159 | console.log('This module is unknown: ' + hyfModule);
160 | }}
161 | ```
162 |
163 | Depending on the value of the expression specified in the `switch` clause, one of the `case` statement blocks is executed. Each statement block should end with a `break` statement to ensure that a `case` doesn't 'fall through' into the next `case`.
164 |
165 | The `default` statement at the end is executed when none of the preceding cases hold true. The `default` statement is not strictly required, but is a best practice to always specify one.
166 |
167 | >More information on MDN: [switch](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/switch)
168 |
169 | ## truthy, falsy
170 |
171 | **truthy**: 'sort of' `true`
172 | **falsy**: 'sort of' `false`
173 |
174 | From MDN:
175 |
176 | In JavaScript, a **truthy** value is a value that is considered true when evaluated in a Boolean context. All values are truthy unless they are defined as **falsy**.
177 |
178 | **falsy** values are:
179 |
180 | - `false`
181 | - `0`
182 | - `""`
183 | - `null`
184 | - `undefined`
185 | - `NaN`
186 |
187 | The example below will print `x is undefined` because `undefined` is **falsy**.
188 |
189 | ```js
190 | let x;
191 | if (x) {
192 | console.log('x is defined');
193 | } else {
194 | console.log('x is undefined');
195 | }
196 | ```
197 |
198 | >More information on MDN: [Truthy](https://developer.mozilla.org/en-US/docs/Glossary/Truthy), [Falsy](https://developer.mozilla.org/en-US/docs/Glossary/Falsy)
--------------------------------------------------------------------------------
/fundamentals/event_loop.md:
--------------------------------------------------------------------------------
1 | # Event Loop
2 |
3 | ## YouTube Video
4 |
5 | This article is a companion to the excellent YouTube video [What the heck is the event loop anyway?](https://www.youtube.com/watch?v=8aGhZQkoFbQ) by Philip Roberts.
6 |
7 | [](https://www.youtube.com/watch?v=8aGhZQkoFbQ "Event Loop")
8 |
9 | ## Introduction
10 |
11 | The way of programming when developing JavaScript applications for the browser is sometimes called _Event-Driven Programming_. Once a JavaScript program has been loaded in the browser and has completed its initialization, it is normally waiting for specific "events" to happen. These events can take the form of mouse movements and clicks, keyboard interactions and network-related events (e.g. a response from an `XMLHttpRequest`)*.
12 |
13 | In order for a JavaScript program to respond to a specific (type of) event, a programmer needs to add an "event listener" for the event type of interest to the target DOM element or network request object.
14 |
15 | Event examples are:
16 |
17 | - a `'click'` event from an HTML button element.
18 | - a `'load'` event from an XMLHttpRequest.
19 |
20 | A JavaScript program can also set up one or more timers and execute a function when a specific timeout expires. One could consider these to be _software-initiated_ events.
21 |
22 | When a event occurs, the browser places an object with information about the event along with the JavaScript function designated to handle the event in an Event Queue. When the JavaScript engine is idle (i.e. when the call stack is empty, see below), it picks up the next event from the Event Queue and invokes the corresponding event handler, passing the event object as a parameter. This mechanism could be depicted by the follow pseudo-code:
23 |
24 | ```
25 | // Event Loop
26 | while (waiting_for_event) {
27 | execute_event_handler(event)
28 | }
29 | ```
30 |
31 |
32 | \* Note: There are more [Web APIs](https://developer.mozilla.org/en-US/docs/Web/API) available in the browser that could potentially generate events, e.g. the [SpeechSynthesis API](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis) and the [MIDIAccess API](https://developer.mozilla.org/en-US/docs/Web/API/MIDIAccess), to name just two.
33 |
34 | ## Call Stack
35 |
36 | The JavaScript engine maintains a [call stack](https://developer.mozilla.org/en-US/docs/Glossary/Call_stack) to keep track of nested function calls. (The call stack is similar to a JavaScript array to which items are pushed and from which items are popped.)
37 |
38 | Figure 1 below depicts the call stack for a scenario where function **A**() calls function **B**(). The currently executing function is always the one at the top of the call stack. In this case, execution starts with function **A**().
39 |
40 | 1. The JavaScript engine pushes **A**() on the call stack and starts its execution.
41 | 2. Function **A**() calls function **B()**: the JavaScript engine suspends the execution of **A**() (taking note where it left off), pushes **B**() on the call stack and starts executing **B**().
42 | 3. When function **B**() returns, the JavaScript engine pops **B**() off the stack. Since function **A**() is now again at the top the stack, the JavaScript engine resumes **A**() at the point where it left off.
43 | 4. Finally, when function **A**() returns it is popped of the stack and with the call stack now empty, the JavaScript engine enters its event loop.
44 |
45 | 
46 |
47 | Figure 1. Call Stack
48 |
49 | ## Example Code
50 |
51 | We will use the example application below for our discussion of the event loop. The application consist of a simple HTML page with three buttons and an associated JavaScript file. The web page looks like this:
52 |
53 | 
54 |
55 | All output resulting from button clicks will be printed in the browser's console.
56 |
57 | ### index.html
58 |
59 | ```html
60 |
61 |
62 |
63 | Sync/Async Demo
64 |
69 |
70 |
71 |
72 |
Sync/Async Demo
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | ```
81 |
82 | ### app.js
83 |
84 | The JavaScript file `app.js` adds a `'click'` event listener for each of the three buttons. Rather than using anonymous functions for the event handlers, all functions are given a name so that these names show up in the call stack should we run this code in the Chrome debugger.
85 |
86 | ```js
87 | 'use strict';
88 | {
89 | function synTimeout(delay) {
90 | const stopTime = Date.now() + delay;
91 | while (Date.now() < stopTime);
92 | }
93 |
94 | function addSyncOnClickListener() {
95 | document
96 | .getElementById('btn-sync')
97 | .addEventListener('click', function onSyncClick() {
98 | console.log('start sync timer');
99 | synTimeout(5000);
100 | console.log('stop sync timer');
101 | });
102 | }
103 |
104 | function addAsyncOnClickListener() {
105 | document
106 | .getElementById('btn-async')
107 | .addEventListener('click', function onAsyncClick() {
108 | console.log('start async timer');
109 | setTimeout(function onTimeout() {
110 | console.log('stop async timer');
111 | }, 5000);
112 | });
113 | }
114 |
115 | function addHelloOnClickListener() {
116 | document
117 | .getElementById('btn-hello')
118 | .addEventListener('click', function onHelloClick() {
119 | console.log('Hello, world!');
120 | });
121 | }
122 |
123 | window.onload = () => {
124 | addSyncOnClickListener();
125 | addAsyncOnClickListener();
126 | addHelloOnClickListener();
127 | };
128 | }
129 | ```
130 |
131 | ### Synchronous, blocking code
132 |
133 | In Figure 2.1 below, when the **START SYNC TIMER** button is clicked ①, a `click` event with its `onSyncClick` event handler is placed in the Event Queue and, because the call stack is empty, is immediately executed. The `onSyncClick` function calls the `synTimeout` function, passing the desired time delay in milliseconds in the `delay` parameter. The call stack at this point in time is depicted in ②.
134 |
135 | The `synTimeout` function keeps racing around in a tight `while` loop, in each loop iteration calling `Date.now()` to check whether the specified delay has already been reached. While the JavaScript engine is busy executing this `while` loop, it cannot run any other code. In particular, it cannot pick up events from the Event Queue, for instance click events from the **HELLO** button, while the loop is executing ③. The `onHelloClick` event handler awaits execution in the Event Queue (with the browser appearing to be unresponsive) until the `synTimeout` function completes, and with it, the `onSyncClick` function (Figure 2.2, ④).
136 |
137 | 
138 |
139 | Figure 2.1 The Event Loop - blocking code.
140 |
141 | At this point the call stack becomes empty, and the event loop can pick up `onHelloClick` from the Event Queue and execute it ⑤. In the browser this is experienced as a delayed, sluggish response to the click on the **HELLO** button.
142 |
143 | Finally, when the `onHelloClick` event handler has finished execution, the call stack becomes empty again ⑥, and the event loop awaits further, future events.
144 |
145 | **In conclusion:** Synchronous, blocking code, such as implemented by
146 | the `synTimeout` function is to be avoided as it makes the application appear to be unresponsive.
147 |
148 | 
149 |
150 | Figure 2.2 The Event Loop - blocking code - continued.
151 |
152 | ## Asynchronous, non-blocking code
153 |
154 | In contrast, in Figure 3.1, when we click the **START ASYNC TIMER** button ①, the `onAsyncClick` event handler is placed and the Event Queue and, because the call stack is empty, is immediately executed ②. It in turn calls the `setTimeout` function provided by the browser (**not** the JavaScript engine!). This starts a timer internal to the browser ③. Once the timer has been set up the `setTimeout` function returns and subsequently the `onAsyncClick` event handler exits.
155 |
156 | Suppose that one second later we click the **HELLO** button ④. This causes the `onHelloClick` event handler to be placed in the Event Queue. Because the call stack is empty the `onHelloClick` event handler is immediately executed ⑤ and subsequently exits.
157 |
158 | 
159 |
160 | Figure 3.1 The Event Loop - non-blocking code.
161 |
162 |
163 | When some time later the timer set up in step 3 expires, the `onTimeout` callback is placed in the event queue ⑥. Again, because the call stack is empty at that point in time it is immediately executed ⑦.
164 |
165 | 
166 |
167 | Figure 3.2 The Event Loop - non-blocking code - continued.
168 |
169 | Subsequently it exits, leaving the call stack empty again ⑧, ready to take on new events from the event loop whenever they occur.
170 |
171 | 
172 |
173 | Figure 3.3 The Event Loop - non-blocking code - continued.
174 |
175 | **In conclusion:** Asynchronous, non-blocking code is to be preferred at all times to ensure that the application maintains its responsiveness.
176 |
177 | ## More Information
178 |
179 | Mozilla Developer Network: [Concurrency model and Event Loop](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop)
--------------------------------------------------------------------------------
/fundamentals/exercises.md:
--------------------------------------------------------------------------------
1 | # JavaScript fundamentals - exercices
2 |
3 | ### Given the following code:
4 |
5 | ```js
6 | let s = "Hello";
7 | let x = s.toLowerCase();
8 | let l = s.length;
9 | ```
10 |
11 | **1. What are the types of the following:**
12 |
13 | 1. `s`
14 | 2. `x`
15 | 3. `s.toLowerCase()`
16 | 4. `s.toLowerCase`
17 | 5. `s.length`
18 | 6. `l`
19 |
20 | ----
21 |
22 | ### 2. In `let x = 5 + 6;`, what is `+`?
23 |
24 | 1. Function
25 | 2. Operator
26 | 3. Number
27 | 4. Aggregator
28 |
29 | ----
30 |
31 | ### 3. In `let x = 5 + 6;`, what is `let`?
32 |
33 | 1. Variable
34 | 2. Keyword
35 | 3. Operator
36 | 4. Constant
37 |
38 | ----
39 |
40 | ### Given the following code:
41 |
42 | ```js
43 | let x = z[y];
44 | ```
45 |
46 | **4. What is `y`?**
47 |
48 | 1. Index
49 | 2. Key
50 | 3. Index or key
51 | 4. Array
52 |
53 | ----
54 |
55 | ### Given the following code:
56 |
57 | ```js
58 | let y = 1;
59 | let x = [1, 2, 3];
60 | let z = x[y];
61 | ```
62 |
63 | **5. What is `y`?**
64 |
65 | 1. Index
66 | 2. Key
67 | 3. Index or key
68 | 4. Array
69 |
70 | ----
71 |
72 | ### Given the following code:
73 |
74 | ```js
75 | let joe = {
76 | name: 'Joe',
77 | age: 24
78 | };
79 | let joesName = joe.name;
80 | let joesAge = joe['age'];
81 | ```
82 |
83 | **6. What is `'age'` in the last line?**
84 |
85 | 1. Index
86 | 2. Key
87 | 3. Array
88 | 4. Object
89 |
90 | **7. What are `name` and `age` of the object `joe`?**
91 |
92 | 1. Index
93 | 2. Key
94 | 3. Object
95 | 4. Property
96 |
97 | ----
98 |
99 | ### Given the following code:
100 |
101 | ```js
102 | let y = 'length';
103 | let x = [1, 2, 3];
104 | let z = x[y];
105 | ```
106 |
107 | **7. What is `y`**
108 |
109 | 1. Index
110 | 2. Key
111 | 3. Index or key
112 | 4. Array
113 |
114 | **8. What is the element for index `1` in array `x`?**
115 |
116 | **9. Fill in: "The value of the (...) `length` of `x` is (...)"**
117 |
118 | ----
119 |
120 | ### 10. What is the name of these functions?
121 |
122 | 1. `function a() { return true; }`
123 | 2. `let a = function b() { return true; }`
124 | 3. `let c = function () { return true; }`
125 |
126 | ----
127 |
128 | ### 11. Write a function that has two parameters called `first` and `second`
129 |
130 | ----
131 |
132 | ### 12. Write a function call that passes three arguments.
133 |
134 | ----
135 |
136 | ### 13. Write code for the following
137 |
138 | 1. Declare a variable called `x` and initialize it with the string "Hello".
139 | 2. Declare a variable called `y` and initialize it with the property `length` of `x`.
140 | 3. Declare a variable called `z` and initialize it with the result of calling the method `toUpperCase` on `x`
141 | 4. Declare a function called `myFunction`. This function should take two arguments, and should call the second argument with the first argument as its argument. Then, declare a variable called `f` and initialize it with an empty anonymous function, and call `myFunction` with the arguments `10` and `f`.
142 |
143 | ----
144 |
145 | ### 14. Explain as precisely as possible (in English) what the following code does, line by line
146 |
147 | (Tip: it should look like the items in the previous question!)
148 |
149 | ```js
150 | let s = "HackYourFuture";
151 | let i = s.indexOf("Your");
152 | function sum(a, b) { return a + b; }
153 | let s = sum(4, 5);
154 | let r = Math.sqrt(s);
155 | ```
156 |
157 | ----
158 |
159 | ### 15. Indicate for each of these whether it is an expression or a statement:
160 |
161 | 1. `l`
162 | 2. `l = 4;`
163 | 3. `l == 4`
164 | 4. `if (l == 4) { console.log("yes"); }`
165 | E. `console.log("yes");`
166 | F. `"yes"`
167 | G. `console.log(l == 4 ? "yes" : "no")`
168 | H. `function a() { return 4; }`
169 | I. `let a = function () { return 4; }`
170 |
171 | ----
172 |
173 | ### 16. How can you tell whether something is a statement?
174 |
175 | ----
176 |
177 | ### 17. How can you tell whether something is an expression
178 |
179 | ----
180 |
181 | ### Given the following code:
182 |
183 | ```js
184 | let s = "Hello".toLowerCase();
185 | let l = s.length;
186 |
187 | function sum(a, b) {
188 | return a + b;
189 | }
190 | let max = function (a, b) {
191 | return a > b ? a : b;
192 | }
193 |
194 | let s1 = sum(4, 5);
195 | let s2 = 4 + 5;
196 |
197 | if (s2 == s1) {
198 | console.log("same");
199 | } else {
200 | console.log("not same");
201 | }
202 | ```
203 |
204 | **18. List all 11 *statements* in the code above**
205 |
206 | **19. List all 28 *expressions* in the code above (BONUS!)**
207 |
--------------------------------------------------------------------------------
/fundamentals/express.md:
--------------------------------------------------------------------------------
1 | # Express
2 |
3 | ## Purpose
4 |
5 | This article gives an overview of Express and how it can be used to build complex HTTP server applications based on the Node.js `http` module.
6 |
7 | ## A simple Express server
8 |
9 | Let's create a simple Express server with Node:
10 |
11 | ```js
12 | const http = require('http');
13 | const express = require('express');
14 | const app = express();
15 |
16 | http.createServer(app)
17 | .listen(3000, () => {
18 | console.log('Express server listening on port 3000');
19 | });
20 | ```
21 |
22 | So, what is `app` here? The `http.createServer()` function is part of the Node.js `http` module. Inspection of the Node.js documentation shows that `createServer()` expects a **request listener** as its argument. This is a function that takes two arguments: a request object and a response object, named here respectively: `req` and `res`.
23 |
24 | ```js
25 | function requestListener(req, res) {
26 | // ...
27 | }
28 | ```
29 |
30 | Therefore, `app` must be (and actually is) a request listener function:
31 |
32 | ```js
33 | function app(req, res) {
34 | // ...
35 | }
36 | ```
37 |
38 | But actually, `app` is far more than that. The Express package adds number of properties to the `app` function. Remember that a JavaScript function is in essence a JavaScript object, although one of a special type. You can add properties to any JavaScript object, including to function objects, such as `app` here.
39 |
40 | Below is a simplified representation of the internals of Express:
41 |
42 | ```js
43 | // Simplified internal implementation of the 'express' Node module
44 |
45 | function createApplication() {
46 | const app = function(req, res) {
47 | // ...
48 | }
49 |
50 | app.use = function use(...middleWareFns) {
51 | // adds middleware shared across all routes
52 | };
53 |
54 | app.get = function get(path, ...middleWareFns) {
55 | // adds middleware for the GET method for a specific route
56 | }
57 |
58 | // etc.
59 |
60 | return app;
61 | }
62 |
63 | module.exports = createApplication;
64 | ```
65 |
66 | ## A real world Express application
67 |
68 | Figure 1 below shows a real world (though trimmed down) example of an Express application (this one is taken from the **Hyfer** application). We will dissect this code snippet in the next sections.
69 |
70 | ```js
71 | const http = require('http');
72 | const express = require('express');
73 | const compression = require('compression');
74 | const bodyParser = require('body-parser');
75 | const cookieParser = require('cookie-parser');
76 | const serveStatic = require('serve-static');
77 |
78 | const app = express();
79 |
80 | // shared middleware for all routes
81 | app.use(bodyParser.json());
82 | app.use(cookieParser());
83 | app.use(serveStatic('./public'));
84 |
85 | // route specific request handlers
86 | app.get('/api/timeline', getTimeLine);
87 | app.get('/api/user/:id', isAuthenticated, getUser);
88 |
89 | http.createServer(app)
90 | .listen(3000, () => {
91 | console.log('Express server listening on port 3000');
92 | });
93 |
94 | // example request handler implementations
95 |
96 | function getTimeLine(req, res) {
97 | //...
98 | res.json(timeline);
99 | }
100 |
101 | function getUser(req, res) {
102 | //...
103 | res.json(user);
104 | }
105 |
106 | function isAuthenticated(req, res, next) {
107 | //...
108 | if (authenticated) {
109 | next();
110 | } else {
111 | // unauthorized
112 | res.sendStatus(401);
113 | }
114 | }
115 | ```
116 |
117 | Listing 1: A real world Express application
118 |
119 | ## Middleware
120 |
121 | In the Express documentation the term **middleware** is used to describe a special type of request handler. It has the following [function signature](https://developer.mozilla.org/en-US/docs/Glossary/Signature/Function):
122 |
123 | ```js
124 | function middlewareFn(req, res, next) {
125 | // ...
126 | }
127 | ```
128 |
129 | Note that a third parameter, `next` is added to the function signature. This `next` parameter is a function that takes no parameters.
130 |
131 | Express constructs a pipeline of middleware functions through which an incoming HTTP request (`req`) is routed and an outgoing HTTP response (`res`) is sent back.
132 |
133 | Each middleware function is expected to either pass on the request to the next function in the pipeline, i.e. by calling `next()`, or send a response itself. In the latter case, handling of the request ends there and then. Otherwise the next middleware function in the pipeline is called.
134 |
135 | Middleware functions can (and usually do) make change to the request object, the response object or both, before passing them on. In fact, this is the main purpose of middleware: adding functionality and information as the request progresses through the pipeline.
136 |
137 | Ultimately there must be some middleware function in the pipeline that sends a response. If not, the client will time out with an error.
138 |
139 | Figure 1 below illustrates the middleware configuration of Listing 1 above.
140 |
141 | 
142 |
143 | Figure 1. Express middleware pipeline representation of Listing 1 code.
144 |
145 | All incoming requests are routed through the common middleware functions added and configured through `app.use()`. Next, the requests are routed to middleware functions based on the request method (e.g. a `GET`) and request path (e.g. `/api/timeline`). These functions are usually added and configured through `app.get()`, `app.post()`, etc.
146 |
147 | Application specific routes are ultimately handled by request handlers at leaf nodes of the pipeline. Because they are leaf nodes, they usually leave out the `next` parameter, as there is no 'next' to pass the request on to.
148 |
149 | ### Conditional middleware
150 |
151 | In Listing 1 and Figure 1 there are two middleware functions that conditionally call `next()`.
152 |
153 | 1. The first one comes from the [serve-static](https://github.com/expressjs/serve-static) middleware. This middleware checks whether the requested URL corresponds to a file (e.g. `index.html`) in the server folder designated for hosting static content. If so, this file is served as the response. If not, the middleware function calls `next()` to continue the pipeline.
154 |
155 | 2. The second one in this example is the function `isAuthenticated()` which test whether the requesting user is authenticated (details on how this is done is left out here). If the requesting user is an authenticated user, then, the request is allowed to pass through. Otherwise an `HTTP 401 - Unauthorized` is sent back, without allowing the request to continue.
156 |
157 | ## Further reading
158 |
159 | There is far more to Express than can be covered in this article.
160 |
161 | - [Official Express site](https://expressjs.com/)
162 | - [HTTP request methods](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods)
163 | - [HTTP response status codes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status)
164 |
--------------------------------------------------------------------------------
/fundamentals/functions.md:
--------------------------------------------------------------------------------
1 | # Functions
2 |
3 | Consider this **function** from [high-school math](https://www.mathplanet.com/education/algebra-2/how-to-graph-functions-and-linear-equations/functions-and-linear-equations):
4 |
5 | > 𝑓(x) = x + 7
6 | >
7 | > _if x = 2 then_
8 | >
9 | > 𝑓(2) = 2 + 7 = 9
10 |
11 | The value of the function 𝑓(x) is dependent on the value you supply for its argument x. (Instead of the term 'argument', sometimes the word 'parameter' is used).
12 |
13 | Here is the equivalent JavaScript function:
14 |
15 | ```js
16 | // function definition
17 | function f(x) {
18 | return x + 7;
19 | }
20 |
21 | // call the function and log its value for x = 2
22 | console.log(f(2)); // -> 9
23 | ```
24 |
25 | This function adds 7 to the value of its argument. Whenever we need to add 7 to some number we can reuse this same function over and over again.
26 |
27 | During execution, the value of x in the function body (the part between the curly braces) is substituted with the value 'passed' during the function call.
28 |
29 | A function thus is a reusable piece of code (see _Why Use Functions_ below). Functions are *very* important in JavaScript, to the extent that some people call JavaScript a "function-oriented" language. As mentioned above, variables can be of type function. In fact, *every function is a variable*.
30 |
31 | The following two pieces of code have the exact same result:
32 |
33 | ```js
34 | function sum(a, b) {
35 | return a + b;
36 | }
37 | ```
38 |
39 | and
40 |
41 | ```js
42 | let sum = function (a, b) {
43 | return a + b;
44 | }
45 | ```
46 |
47 | > Note
48 | >
49 | > This is not entirely true, as in the second code, the function is "anonymous", i.e. it has no name. But in both cases, you can call the function like this: `sum(4, 5)`.
50 |
51 | ## Parameters & arguments
52 |
53 | When writing `function sum(a, b)`, `a` and `b` are the "parameters" of the function. We say that this function has two parameters. (Sometimes, you'll see the word "arity": this function has "arity" 2, but that is something you don't have to use for now.)
54 |
55 | Now, when *calling* function sum, e.g. `let s = sum(4, 5);`, we say that the numbers `4` and `5` are the "arguments" of the function. Arguments are "passed" to the function: "we pass `4` and `5` to the function `sum`".
56 |
57 | So remember the difference between the word "parameter" and "argument". Many people confuse them, and that's not a big problem, but understanding the difference is always nice:
58 |
59 | * A parameter is the name you want to give to the variable that is available inside of the function.
60 | * An argument is the actual value you want to assign to the parameters when you call the function.
61 |
62 | A function that "has two parameters" is also said to "take/accept two arguments". But, sometimes you'll hear people say: "the function has two arguments" or "the function takes two parameters". While formally incorrect, you'll know what they mean.
63 |
64 | ## Calling a function on something
65 |
66 | In JavaScript, you can call functions *on* something. By this, we mean that you use the dot to call the function. For instance, when we say "call method `trim` on string `s`", we mean:
67 |
68 | ```js
69 | let s = " this is a string ";
70 | s.trim(); // -> "this is a string"
71 | ```
72 |
73 | > Note
74 | >
75 | > Technically, this means that the string `s` will become the `this` special variable inside of the function.
76 |
77 | However, there are functions that you don't call on anything:
78 |
79 | ```js
80 | function sum(a, b) { return a + b; }
81 | sum(4, 5); // -> 9
82 | ```
83 |
84 | Here, you call the function `sum` on nothing.
85 |
86 | Most built-in functions in JavaScript, like math functions or logging functions, also use the dot:
87 |
88 | ```js
89 | Math.round(4.5);
90 | console.log("hello");
91 | Array.from([1, 2, 3]);
92 | ```
93 |
94 | Indeed, these functions are also called "on" `Math`, `console`, `Array`, and so on. However, in this case, their purpose is more to group them logically, so here it's not very important to use that terminology. We'd rather say: "call the function `Math.round` with `4.5` as an argument", i.e. we include it in the full name of the methods.
95 |
96 | It's more when you think about which functions you can call "on" your own variables (strings, arrays, numbers, etc):
97 |
98 | ```js
99 | myString.trim();
100 | myArray.slice();
101 | myNumber.toString();
102 | ...
103 | ```
104 |
105 | ## Why Use Functions?
106 |
107 | > The following was adapted from https://www.cs.utah.edu/~zachary/computing/lessons/uces-10/uces-10/node11.html
108 |
109 | The first reason is **reusability**. Once a function is defined, it can be used over and over and over again. You can invoke the same function many times in your program, which saves you work.
110 |
111 | Another aspect of reusability is that a single function can be used in several different (and separate) programs. When you need to write a new program, you can go back to your old programs, find the functions you need, and reuse those functions in your new program. You can also reuse functions that somebody else has written for you.
112 |
113 | The second reason is **abstraction**. In order to use a particular function you need to know the following things:
114 |
115 | 1. The name of the function;
116 | 2. What the function does;
117 | 3. What arguments you must give to the function; and
118 | 4. What kind of result the function returns.
119 |
120 | But notice: If you just want to use the function in your program, you don't have to know how it works inside! You don't have to understand anything about what goes on inside the function.
121 |
122 | It's sort of like driving a car or using a telephone. With an automobile, you don't need to understand every detail about the engine and drive train and wheels, if all you want to do is drive the car. Similarly, with a telephone, you don't have to understand everything about the phone system in order to make a call.
123 |
124 | The only time you need to know how a function works inside is when you need to write the function, or change how it works. (It's like a car again; you need to know how a car works in order to build one or fix one.) But once a function is written and working, you never need to look at its insides again.
125 |
126 | Together, these two reasons make functions extremely useful--practically essential!-for programmers who write large programs. The ability to divide a program into abstract, reusable pieces is what makes it possible to write large programs that actually work right.
--------------------------------------------------------------------------------
/fundamentals/homework_pr.md:
--------------------------------------------------------------------------------
1 | # Handing in homework
2 |
3 | Starting with the JavaScript2 module we expect you to hand in homework by using the GitHub [Forking Workflow](https://github.com/HackYourFuture/Git/blob/master/Lecture-3.md). This involves the following steps:
4 |
5 | ## Forking
6 |
7 | 1. Go to the [HackYourFuture GitHub page](https://github.com/HackYourFuture) and click on the repository of the current HYF module, e.g. `JavaScript2`.
8 |
9 | 2. In the upper-right corner, press the [**Fork**] button.
10 |
11 | 3. On the subsequent dialog box, select your own GitHub account as the place to fork this repository to.
12 |
13 | 4. After a couple of seconds, you will be taken to your own GitHub account, in the repository just forked.
14 |
15 | 5. Now, clone this forked repository (_not the original HYF one!_) to your laptop.
16 |
17 | ## Commit and Push
18 |
19 | For each week's homework repeat the following steps.
20 |
21 | 1. If there are any outstanding changes from the previous week, either commit or discard them.
22 |
23 | 2. Start afresh by resetting your local repository back to the `master` branch. This ensures that the new homework is not mixed up with the homework of previous weeks. (That previous homework will still be available in their respective branches.) Use this command:
24 |
25 | ```
26 | git checkout master
27 | ```
28 |
29 | 3. Create a new branch for this week's homework (replace `new-branch-name` with the name of your new branch, e.g. 'homework-week1'):
30 |
31 | ```
32 | git checkout -b new-branch-name
33 | ```
34 |
35 | 4. Make changes to your local working directory as required by the homework assignment(s).
36 |
37 | 5. Commit your changes as and when required. The recommended way to add and commit files is to keep a `.gitignore` file in the root folder of your working directory that lists all the files and directories you want to leave untracked by Git. Now, when you use a `git add .` command, all new, changed and/or deleted files, except those from `.gitignore`, are added to the staging area.
38 |
39 | ```
40 | git add .
41 | git commit -m "your commit message"
42 | ```
43 |
44 | Make sure that your commit messages are meaningful and accurately describe what the commit is about. Messages such as `my changes` are not okay. If you need to go back in time to review a particular change from the past, the commit messages are the only clues to go by for finding the relevant commit. For an in-depth discussion on how to write good commit messages, see [How to Write a Git Commit Message](https://chris.beams.io/posts/git-commit/).
45 |
46 | 6. Push your commits to GitHub. You don't need to do this after every individual commit, but pushing often to your own repository is advisable as a safeguard against disk failure on your laptop. The first time you push your new branch you must use the following command (replace `new-branch-name` with the name of your new branch, e.g. 'homework-week1'):
47 |
48 | ```
49 | git push -u origin new-branch-name
50 | ```
51 |
52 | Subsequent pushes can simply be done with:
53 |
54 | ```
55 | git push
56 | ```
57 |
58 | ## Create Pull Request
59 |
60 | When you have finished your homework and wish to hand it in, do so via a **pull request** (PR).
61 |
62 | 1. Make sure that you committed and pushed your final changes in the working directory.
63 |
64 | 2. Go the your GitHub account and select the repository containing your homework.
65 |
66 | 3. Click the button [**New pull request**].
67 |
68 | 4. Select the HackYourFuture repository master branch on the left side and your repository and homework branch on the right side.
69 |
70 | 5. Press the green [**Create pull request**] button to continue.
71 |
72 | 6. Add a title for your pull request, e.g. 'Homework Week 1'. You can optionally add comments for the pull request reviewer, e.g. known issues with your current homework.
73 |
74 | 7. Finally, press the green [**Create pull request**] button to finish sending off the pull request.
75 |
76 | ## Resources
77 |
78 | Take a look at [this video](https://www.youtube.com/watch?v=-o0yomUVVpU)
79 | made by Daan, where he explains this process in detail.
80 |
81 | Also review the [Git workflow material](https://github.com/HackYourFuture/Git/blob/master/Lecture-3.md)
82 | and use it as a reference.
83 |
--------------------------------------------------------------------------------
/fundamentals/javascript_review.md:
--------------------------------------------------------------------------------
1 | ### JavaScript review
2 |
3 | You'll need to know the following before starting the Node class (remember Node is just JavaScript in a different environment - and you KNOW JS already - right?!?!)
4 |
5 | ```
6 | From Jason:
7 | jason [9:11 AM]
8 | @timirkaria the most important topics will be sync/async and ajax. That and basic syntax (named and anonymous functions, callbacks, scope) should be sufficient!
9 | ```
10 |
11 | ### AJAX
12 | Stands for *A*synchronous *J*avascript *A*nd *X*ml (think of XML as the old JSON) but now it's AJA*J* but that doesn't sound as good.
13 |
14 | So here's an example of a SYNCHRONOUS request (it waits for the request to come back before continuing)
15 |
16 | Code from: `https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Synchronous_and_Asynchronous_Requests#Example_HTTP_synchronous_request`
17 |
18 | ```js
19 | const SECRET_MESSAGE_URL = 'https://gist.githubusercontent.com/tkaria/08325583e7411f7de6b80871780fd917/raw/61dae2869ae5013652bbeba1da2487097d8869b1/SecretMessage.txt'
20 | const request = new XMLHttpRequest(SECRET_MESSAGE_URL);
21 | request.open('GET', SECRET_MESSAGE_URL, false); // `false` makes the request synchronous
22 | request.send(null);
23 |
24 | if (request.status === 200) {
25 | console.log(request.responseText);
26 | console.log('Received the response');
27 | }
28 | console.log('Made the request')
29 |
30 | ```
31 |
32 | And here's an example of an ASYNCHRONOUS version of the same request as above. Look carefully at the output.
33 |
34 | ```js
35 | const SECRET_MESSAGE_URL = 'https://gist.githubusercontent.com/tkaria/08325583e7411f7de6b80871780fd917/raw/61dae2869ae5013652bbeba1da2487097d8869b1/SecretMessage.txt'
36 | const xhr = new XMLHttpRequest();
37 | xhr.open("GET", SECRET_MESSAGE_URL, true);
38 | xhr.onload = function (e) {
39 | if (xhr.readyState === 4) {
40 | if (xhr.status === 200) {
41 | console.log(xhr.responseText);
42 | console.log('Received the response');
43 | } else {
44 | console.error(xhr.statusText);
45 | }
46 | }
47 | };
48 | xhr.onerror = function (e) {
49 | console.error(xhr.statusText);
50 | };
51 | xhr.send(null);
52 | console.log('Made the request');
53 | ```
54 |
55 | ### What's happening here?
56 | As always - read the docs first...
57 | `https://developer.mozilla.org/en/docs/Web/API/XMLHttpRequest`
58 |
59 | Create a new request and open it (lines 2 and 3)
60 | Tell the request object what function to call when when the contents of the request are loaded. Inside the ANONYMOUS function which takes a parameter `e` we check the response code from the request (this is just HTTP stuff - nothing special). If the response code is good (200) then we print what we got.
61 |
62 | More interesting is the order of the print statements. In the first example we saw the message `Received the response` **BEFORE** we saw the `Made the request` message because the program waited to get the response and print it before continuing to run.
63 |
64 | In this case we see the `Made the request` message before we see the response because the program keeps running while waiting for the response. When the response is finally received it is printed before writing the `Received the response` to the console.
65 |
66 | Note that we used an anonymous function here - it has no name. There's nothing special about an anonymous function. We could equally use a named function in the above example:
67 |
68 | ```js
69 | const SECRET_MESSAGE_URL = 'https://gist.githubusercontent.com/tkaria/08325583e7411f7de6b80871780fd917/raw/61dae2869ae5013652bbeba1da2487097d8869b1/SecretMessage.txt'
70 |
71 | const xhr = new XMLHttpRequest();
72 | function NOT_ANONYMOUS_ON_LOAD_FUNCTION(parameter) {
73 | if (xhr.readyState === 4) {
74 | if (xhr.status === 200) {
75 | console.log(xhr.responseText);
76 | console.log('Received the response');
77 | } else {
78 | console.error(xhr.statusText);
79 | }
80 | }
81 | }
82 | xhr.open("GET", SECRET_MESSAGE_URL, true);
83 | xhr.onload = NOT_ANONYMOUS_ON_LOAD_FUNCTION; // Note: we are not CALLING the function - there are no ()
84 | // We'll leave the error function the way it is and you can change it to a named function
85 | xhr.onerror = function (e) {
86 | console.error(xhr.statusText);
87 | };
88 | xhr.send(null);
89 | console.log('Made the request');
90 |
91 | ```
92 |
93 | ### The big idea:
94 |
95 | #### Sync / Async
96 | Make requests without waiting for the response and just get "notified" when the response happens. That's the asynchronous part - don't wait for it and stop everything else just let me know when it happens. How can the computer let you know? You tell it what to do when the async function is ready (has something to say - success or failure)
97 |
98 | #### Named and anonymous functions
99 | Some functions have names and some don't. Sometimes you just want to use a function to pass it to another function so you don't need to name it. It never needs to be called outside of the function that you're passing it to so it doesn't need a name.
100 | The simplest asynchronous function that you will see all over the place is called `setTimeout` (right now you should be reaching for a new tab and typing `MDN setTimeout` into Google). Be patient when running the below - it takes 3 seconds...
101 |
102 | For example (using a named function):
103 | ```js
104 | function timeoutFunction() {
105 | console.log('Starting timeoutFunction');
106 | console.log('Ending timeoutFunction');
107 | }
108 | setTimeout(timeoutFunction, 3000);
109 | console.log('After timeoutFunction');
110 | ```
111 |
112 | For example (using an anonymous function):
113 | ```js
114 | setTimeout(function() {
115 | console.log('Starting timeoutFunction');
116 | console.log('Ending timeoutFunction');
117 | } , 3000);
118 | console.log('After timeoutFunction');
119 | ```
120 |
121 | For example (using an anonymous fat arrow function):
122 | ```js
123 | setTimeout(() => { console.log('Starting timeoutFunction');
124 | console.log('Ending timeoutFunction');
125 | } , 3000);
126 | console.log('After timeoutFunction');
127 | ```
128 |
129 | #### Callbacks
130 | What to do when the result of an async request is returned. Remember that requests can succeed as well as fail. Plan for (AND TEST) both.
131 |
132 | #### Scope
133 | I think we covered this pretty well with our discussion of closures in the last class but let me know if you need more.
134 |
135 | ## Recap
136 | Read this - you may not understand it all but please read it before you read anything else about closures. The reason is that this is source material - this is the primary documentation. It is written very technically and in a bit of a boring way but there's a reason (as we talked about in class). The reason is to be clear so the language is precise and technical. It's OK if you don't get it now but just read it and it will stay in the back of your head.
137 | https://developer.mozilla.org/en/docs/Web/JavaScript/Closures
138 |
139 | Please TYPE these exercises - do NOT copy and paste. BEFORE you run them please make a guess in your head about what will happen.
140 | ```js
141 | function init() {
142 | const name = 'Mozilla'; // name is a local variable created by init
143 | function displayName() { // displayName() is the inner function, a closure
144 | alert(name); // use variable declared in the parent function
145 | }
146 | displayName();
147 | }
148 | init();
149 | ```
150 |
151 | ```js
152 | function init() {
153 | const name = 'Mozilla'; // name is a local variable created by init
154 | function displayName() { // displayName() is the inner function, a closure
155 | alert(name); // use variable declared in the parent function
156 | }
157 | }
158 | displayName();
159 | ```
160 |
161 | ```js
162 | const name = 'Hack your future'
163 | function init() {
164 | const name = 'Mozilla'; // name is a local variable created by init
165 | function displayName() { // displayName() is the inner function, a closure
166 | alert(name); // use variable declared in the parent function
167 | }
168 | displayName();
169 | }
170 | init();
171 | ```
172 |
173 | ```js
174 | const name = 'Hack your future'
175 | function init(name) {
176 | function displayName(name) { // displayName() is the inner function, a closure
177 | alert(name); // use variable declared in the parent function
178 | }
179 | displayName(name);
180 | }
181 | init('Hack your future again')
182 | ```
183 |
184 | Now read this: http://stackoverflow.com/questions/11488014/asynchronous-process-inside-a-javascript-for-loop
185 |
186 | And try out the examples - please make SURE you understand what is happening. Ask questions if you do not.
187 |
188 | Same instructions as above but now for Arrow functions (remember this is not intended to confuse you - it's just code).
189 |
190 | ### Arrow functions
191 | https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions
192 | Then read this.
193 | http://stackoverflow.com/questions/22939130/when-should-i-use-arrow-functions-in-ecmascript-6/28135120#28135120
194 |
195 | This is a normal function:
196 | ```js
197 | function sayHello(name) {
198 | return 'Hello ' + name;
199 | }
200 | ```
201 |
202 | Same as above with arrow (fat arrow) notation - shorthand notation. This is easy to mess up. Notice no return.
203 | ```js
204 | const sayHello2 = (name) => 'Hello ' + name;
205 | ```
206 |
207 | Same as above with arrow (fat arrow) notation - shorthand notation. Better - easier to read - with return.
208 | ```js
209 | const sayHello2 = (name) => {return 'Hello ' + name;}
210 | ```
211 |
212 | Think about this one
213 | ``` js
214 | function Person(firstName) {
215 | this.firstName = firstName;
216 | }
217 | ```
218 |
219 | Looks the same but what happens? See if you can figure out why from reading the documentation.
220 | ```js
221 | const Person = (firstName) => {this.firstName = firstName}
222 | ```
223 |
224 | Closures and async functions
225 | What's going on here - I would expect 3 alerts with 1,2,3 in them but noooooooooo
226 | ```js
227 | for (var i = 0; i < 3; i++) {
228 | setTimeout(function callBackFunction() {
229 | alert(i);
230 | }, 100);
231 | }
232 | ```
233 |
234 | ### Make the above function do what we think it should do.
235 |
236 | ### Return examples
237 | ```js
238 | Return values
239 | function f1(x) {
240 | this.x = x + 1;
241 | return;
242 | }
243 |
244 | function f2(x) {
245 | return this.x = x + 1;
246 | }
247 | ```
248 |
249 | ### Static members
250 | http://odetocode.com/blogs/scott/archive/2015/02/02/static-members-in-es6.aspx
251 |
252 | ### Closures examples
253 | https://jsfiddle.net/78dg25ax/?utm_source=website&utm_medium=embed&utm_campaign=78dg25ax
254 |
255 | ### Why closures are helpful with async code:
256 | http://stackoverflow.com/questions/13343340/calling-an-asynchronous-function-within-a-for-loop-in-javascript
257 |
258 | ### Promises
259 | http://stackoverflow.com/questions/13343340/calling-an-asynchronous-function-within-a-for-loop-in-javascript
260 | https://www.youtube.com/watch?v=WBupia9oidU
261 |
262 |
--------------------------------------------------------------------------------
/fundamentals/loops.md:
--------------------------------------------------------------------------------
1 | # Loops
2 |
3 | A loop is a programming construct to perform a repetitive action. Often (but not always) the repetitive action involves accessing or manipulating the individual elements of an array.
4 |
5 | We will use the array of month names given below to illustrate the various types of loop constructs available in JavaScript. In the examples we will print out the names of the individual months using a `console.log` statement.
6 |
7 | ```js
8 | const months = [
9 | 'January',
10 | 'February',
11 | 'March',
12 | 'April',
13 | 'May',
14 | 'June',
15 | 'July',
16 | 'August',
17 | 'September',
18 | 'October',
19 | 'November',
20 | 'December',
21 | ];
22 | ```
23 |
24 | ## while
25 |
26 | The `while` loop is probably the simplest one of the bunch. Its general syntax is:
27 |
28 | ```js
29 | while (cond) {
30 | // statement block to be repeated
31 | }
32 | ```
33 |
34 | The loop 'body' (i.e., the statement block including the curly braces) is executed while the condition `cond` holds true. In order for this while loop to execute at least once and to finish in finite time two preconditions must be fulfilled:
35 |
36 | 1. The condition `cond` should initially hold true.
37 | 2. Some code inside the code block must eventually cause the condition to become false.
38 |
39 | Applied to our `months` array the while loop would look like this:
40 |
41 | ```js
42 | const months = [
43 | ...
44 | ];
45 |
46 | let index = 0;
47 | const len = months.length; // 12
48 |
49 | while (index < len) {
50 | console.log(months[index]);
51 | index += 1;
52 | }
53 | ```
54 |
55 | In this example the two preconditions mentioned earlier are met:
56 |
57 | 1. The condition `index < len` initially holds true because `index` is initialized to `0` and we know that `len` is fixed at the value of `12` (hence the use of `const` rather than `let`).
58 | 2. Because the value of `index` is incremented by one each time the loop body is executed there will be a point in time when the loop condition becomes false. This will happen when the value `index` has become `12` and `index < len` no longer holds true.
59 |
60 | If precondition 2 is **not** met then your loop will execute forever. This is what is commonly referred to as an _infinite loop_. Your code will appear to 'hang' when this happens, and you will need to somehow terminate the program and fix the problem (e.g., press Ctrl-C when running in Node).
61 |
62 | More info on MDN: [while](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/while)
63 |
64 | ## do...while
65 |
66 | This is a variation of the while loop discussed above. Its general syntax is:
67 |
68 | ```js
69 | do {
70 | // statement block to be repeated
71 | } while (cond);
72 | ```
73 |
74 | The do...while loop is executed at least once, because the loop condition is evaluated at the _end_ of the loop rather than at the _beginning_ as is the case with the regular `while` loop.
75 |
76 | Applied to our 'months' example the code would look like this:
77 |
78 | ```js
79 | const months = [
80 | ...
81 | ];
82 |
83 | let index = 0;
84 | const len = months.length;
85 |
86 | do {
87 | console.log(months[index]);
88 | index += 1;
89 | } while (index < len)
90 | ```
91 |
92 | We recommend that you do not use the `do...while` loop, exactly for the reason that the loop body is executed at least once without taking the loop condition into account. It is always possible to rewrite a `do...while` loop into a regular `while` loop that strictly meets the two preconditions mentioned earlier.
93 |
94 | 
95 |
96 | More info on MDN: [do...while](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/do...while)
97 |
98 | ## for
99 |
100 | The `for` loop is the most used loop construct that you will come across and that you are likely to use most in your own code. It exists in a number of variations in JavaScript that we will cover one by one below. The syntax of the most generic form is as follows:
101 |
102 | ```js
103 | for ([initialization]; [condition]; [final - expression]) {
104 | // statement block to be repeated
105 | }
106 | ```
107 |
108 | Let's first look at an example:
109 |
110 | ```js
111 | const months = [
112 | ...
113 | ];
114 |
115 | const len = months.length;
116 |
117 | for (let index = 0; index < len; index++) {
118 | console.log(months[index]);
119 | }
120 | ```
121 |
122 | The `for` statement combines three parts of the loop construct in a single statement. Those three parts are separated by semicolons and, enclosed within parentheses, directly follow the `for` keyword.
123 |
124 | 1. The first part is the for loop initialization of a loop 'index' variable, here called `index`. (Often you will see one letter variable names, such as `i` for the loop index.). This part is executed only once.
125 | 2. The second part is the loop condition, and is evaluated for every loop [iteration](http://www.dictionary.com/browse/iteration). The loop body is executed while this condition holds true. Note that this condition is tested at the beginning of the loop (like `while` above) and **not** at the end (like `do...while`).
126 | 3. The last part is where the loop index variable is updated, in this case incremented by one (`index++` is short for `index += 1`, which in itself is short for `index = index + 1`). This update is effectively done at the end of the loop (in the example, after the console.log has been executed).
127 |
128 | This form of the `for` loop is roughly equivalent1 to the following:
129 |
130 | ```js
131 | // for (let index = 0; index < len; index++) {
132 | // ↑A ↑B ↑C
133 |
134 | let index = 0; // ← A
135 | while (index < len) {
136 | // ← B
137 | console.log(months[index]);
138 | index++; // ← C
139 | }
140 | ```
141 |
142 | 1 In this `while` loop version, the `index` variable is accessible both inside and outside of the loop body (i.e., the code block inside the curly braces). In the case of an equivalent `for` loop, the scope of the index variable depends on whether it is declared with `let` or `var`. See this [article from Web Bos](http://wesbos.com/for-of-es6/) for details.
143 |
144 | More info on MDN: [for](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for)
145 |
146 | ## for...of
147 |
148 | The `for...of` loop construct is relatively new and very well suited for use with arrays. It was introduced with the ES6 variant of JavaScript. Its general syntax is:
149 |
150 | ```js
151 | for (variable of iterable) {
152 | // statement block to be repeated
153 | }
154 | ```
155 |
156 | Here, `iterable` can be a couple of things, but most of the time it is just an array variable. Let's again look at an example.
157 |
158 | ```js
159 | const months = [
160 | ...
161 | ];
162 |
163 | for (const month of months) {
164 | console.log(month);
165 | }
166 | ```
167 |
168 | With this `for` loop variant, the array is considered a collection of elements (you can _iterate_ through a collection: it is 'iterable'). Each time the loop body is executed the loop variable receives the next value of the array (in the example, starting with `'January'` and ending with `'December'`).
169 |
170 | This now allows us to write very elegant and short code. No need to mess around with a loop index variable, array lengths etc. If you need to use a `for` loop involving arrays, this will often be your first choice.
171 |
172 | More on MDN: [for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of)
173 |
174 | ## for..in
175 |
176 | This loop variant is for use with JavaScript objects only. It existed before the `for...of` loop variant became available.
177 |
178 | We will discuss the `for...in` variant in more detail the part of the curriculum where we deal with Objects. Here, we will suffice to say that the `for...in` loop construct can easily be rewritten as a `for...of` loop, as follows:
179 |
180 | ```js
181 | const obj = {
182 | a: 10,
183 | b: 'test',
184 | };
185 |
186 | // for...in
187 | for (const key in obj) {
188 | console.log(obj[key]);
189 | }
190 |
191 | // equivalent for...of
192 | for (const key of Object.keys(obj)) {
193 | console.log(obj[key]);
194 | }
195 | ```
196 |
197 | More info on MDN: [for...in](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in)
198 |
199 | ## Array.forEach()
200 |
201 | The `.forEach()` array method can be used to iterate over all the elements of an array in functional away. This is explained in detail in the fundamental on array methods: [Array.forEach()](https://github.com/HackYourFuture/fundamentals/blob/master/fundamentals/map_filter.md#arrayforeach). Many programmers prefer this functional way over traditional loops when working with arrays.
202 |
--------------------------------------------------------------------------------
/fundamentals/map_filter.md:
--------------------------------------------------------------------------------
1 | # forEach, map, filter, reduce
2 |
3 | The array methods **forEach**, **map**, **filter** and **reduce** are best understood by looking at how they might be implemented if you had to write them yourself in JavaScript. In the next few sections we will present simplified equivalents of the native implementations.
4 |
5 | Common to these methods is that they all use a **for** loop internally to iterate through the elements of the target array. When working with arrays, many developers prefer these methods rather than using a **for** loop in their code. By virtue of their names they reveal more clearly what is intended than equivalent **for** loops, which must be examined more closely to determine what is going on.
6 |
7 | ## Array.forEach()
8 |
9 | > [MDN definition](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach): The **forEach()** method executes a provided function once for each array element.
10 |
11 | ```js
12 | const numbers = [1, 2, 3, 4];
13 | let sum = 0;
14 |
15 | numbers.forEach(x => {
16 | sum += x;
17 | });
18 |
19 | console.log(sum); // -> 10
20 | ```
21 |
22 | > _See this in action in this [JSBin](https://jsbin.com/quforih/edit?js,console)._
23 |
24 | ### A custom forEach() implementation
25 |
26 | ```js
27 | function forEach(arr, func) {
28 | for (let i = 0; i < arr.length; i++) {
29 | func(arr[i], i, arr);
30 | }
31 | }
32 |
33 | const numbers = [1, 2, 3, 4];
34 | let sum = 0;
35 |
36 | forEach(numbers, x => {
37 | sum += x;
38 | });
39 |
40 | console.log(sum); // -> 10
41 | ```
42 |
43 | > _See this in action in this [JSBin](https://jsbin.com/bufamuz/edit?js,console)._
44 |
45 | ### Calling forEach() as a method on an array
46 |
47 | To demonstrate how we can use dot notation directly on an array to call our custom `forEach()` function, similar to how the native, built-in `.forEach()` method works, we will add a new method `.myForEach()` to the native `Array` type that in turn calls our `forEach()` function.
48 |
49 | > _Note that it is considered a bad practice to modify built-in JavaScript types like is done here. You should not do this in production code. We show it here for demonstration purposes only._
50 |
51 | ```js
52 | function forEach(arr, func) {
53 | for (let i = 0; i < arr.length; i++) {
54 | func(arr[i], i, arr);
55 | }
56 | }
57 |
58 | Array.prototype.myForEach = function(func) {
59 | forEach(this, func);
60 | };
61 |
62 | const numbers = [1, 2, 3, 4];
63 | let sum = 0;
64 |
65 | numbers.myForEach(x => {
66 | sum += x;
67 | });
68 |
69 | console.log(sum); // -> 10
70 | ```
71 |
72 | > _See this in action in this [JSBin](https://jsbin.com/pehexug/edit?js,console)._
73 |
74 | ### The callback function
75 |
76 | For illustrative purposes we can add a `console.log` statement to the callback function and see what is passed as the second and third argument:
77 |
78 | ```js
79 | const numbers = [1, 2, 3, 4];
80 |
81 | numbers.forEach((elem, index, arr) => {
82 | console.log('elem: ' + elem + ', index: ' + index + ', arr: ' + arr);
83 | });
84 |
85 | /* output:
86 | elem: 1, index: 0, arr: 1,2,3,4
87 | elem: 2, index: 1, arr: 1,2,3,4
88 | elem: 3, index: 2, arr: 1,2,3,4
89 | elem: 4, index: 3, arr: 1,2,3,4
90 | */
91 | ```
92 |
93 | > _See this in action in this [JSBin](https://jsbin.com/nohipew/edit?js,console)._
94 |
95 | The first value is the value of the current element, the second value is the current loop index value and the array value is the array on which `.forEach()` is called.
96 |
97 | As is common in JavaScript, you do not necessarily have to use all the parameters that are passed to the callback function. In fact, in many cases you will only need the first argument (the current array element).
98 |
99 | Note that the callback functions for **map**, **filter** and **reduce**, as described below, receive the same three arguments, here named `elem`, `index` and `arr`.
100 |
101 | ## Array.map()
102 |
103 | > [MDN definition](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map): The **map()** method creates a new array with the results of calling a provided function on every element in the calling array.
104 |
105 | ```js
106 | const numbers = [1, 2, 3, 4];
107 | const square = x => x * x;
108 | const squaredNumbers = numbers.map(square);
109 |
110 | console.log(squaredNumbers); // -> [ 1, 4, 9, 16 ]
111 | ```
112 |
113 | > _See this in action in this [JSBin](https://jsbin.com/wewewej/edit?js,console)._
114 |
115 | ### A custom map() implementation
116 |
117 | The **map()** function below initializes a new, empty array to which it pushes _transformed_ elements, one by one, as it iterates through the array argument `arr`, calling the `mapFn` function for each individual element. When the loop has been completed, the new array is returned. Note that the array `arr` itself remains unmodified.
118 |
119 | ```js
120 | function map(arr, mapFn) {
121 | const result = [];
122 | for (let i = 0; i < arr.length; i++) {
123 | const mappedValue = mapFn(arr[i], i, arr);
124 | result.push(mappedValue);
125 | }
126 | return result;
127 | }
128 |
129 | const numbers = [1, 2, 3, 4];
130 | const square = x => x * x;
131 | const squaredNumbers = map(numbers, square);
132 |
133 | console.log(squaredNumbers); // -> [1, 4, 9, 16]
134 | ```
135 |
136 | > _See this in action in this [JSBin](https://jsbin.com/winudul/edit?js,console)._
137 |
138 | To prevent unintended results it is essential that the function passed as the `mapFn` argument does not modify the original array. In computer science terms, this function should be _pure_, without side effects.
139 |
140 | > - Read more: [What is a pure function?](https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976)
141 |
142 | ## Array.filter()
143 |
144 | > [MDN definition](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter): The **filter()** method creates a new array with all elements that pass the test implemented by the provided function.
145 |
146 | ```js
147 | const numbers = [1, 2, 3, 4];
148 | const isEven = x => x % 2 === 0;
149 | const evenNumbers = numbers.filter(isEven);
150 |
151 | console.log(evenNumbers); // -> [ 2, 4 ]
152 | ```
153 |
154 | > _See this in action in this [JSBin](https://jsbin.com/zepemuc/edit?js,console)._
155 |
156 | ### A custom filter() implementation
157 |
158 | This method works in a similar fashion as the `map()` method, but now elements are only pushed to the new array if the predicate function returns `true`. The new array will (potentially) have fewer elements than the original array, but the filtered elements are not changed in any way.
159 |
160 | In the example below the predicate function test whether the current element is even by checking whether its value divided by two has a remainder of zero. The result of this comparison (`true` or `false`) is the return value of the predicate and determines whether the current element gets added to the new array or not.
161 |
162 | ```js
163 | function filter(arr, predicateFn) {
164 | const result = [];
165 | for (let i = 0; i < arr.length; i++) {
166 | if (predicateFn(arr[i], i, arr)) {
167 | result.push(arr[i]);
168 | }
169 | }
170 | return result;
171 | }
172 |
173 | const numbers = [1, 2, 3, 4];
174 | const isEven = x => x % 2 === 0;
175 | const evenNumbers = filter(numbers, isEven);
176 |
177 | console.log(evenNumbers); // -> [2, 4]
178 | ```
179 |
180 | > _See this in action in this [JSBin](https://jsbin.com/nugibag/edit?js,console)._
181 |
182 | \*A _predicate_ is a function that returns a boolean, **true** or **false**, depending on the supplied arguments.
183 |
184 | ## Array.reduce()
185 |
186 | > [MDN definition](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce): The **reduce()** method executes a **reducer** function (that you provide) on each member of the array resulting in a single output value†.
187 |
188 | †Although reference is made to a 'single output value', this single value may well be an array or an object, as you will see later in the examples below.
189 |
190 | ```js
191 | const numbers = [1, 2, 3, 4];
192 |
193 | const sum = (a, b) => a + b;
194 | const total = numbers.reduce(sum, 0);
195 |
196 | console.log(total); // -> 10
197 | ```
198 |
199 | > _See this in action in this [JSBin](https://jsbin.com/sutamiy/edit?js,console)._
200 |
201 | ### A custom reduce() implementation
202 |
203 | ```js
204 | function reduce(arr, reducerFn, initialValue) {
205 | let accumulator = initialValue;
206 | for (let i = 0; i < arr.length; i++) {
207 | accumulator = reducerFn(accumulator, arr[i], i, arr);
208 | }
209 | return accumulator;
210 | }
211 |
212 | const numbers = [1, 2, 3, 4];
213 |
214 | const sum = (a, b) => a + b;
215 | const total = reduce(numbers, sum, 0);
216 |
217 | console.log(total); // -> 10
218 | ```
219 |
220 | > _See this in action in this [JSBin](https://jsbin.com/jofojej/edit?js,console)._
221 |
222 | The key to understanding the **reduce()** method is in the line:
223 |
224 | ```js
225 | accumulator = reducerFn(accumulator, arr[i], i, arr);
226 | ```
227 |
228 | In the case we don't need the current loop index and the subject array in the reducer function (which is often the case), we can simplify this to:
229 |
230 | ```js
231 | accumulator = reducerFn(accumulator, arr[i]);
232 | ```
233 |
234 | From this line we can define the reducer function as a function that takes an accumulator value and the current array element and returns a new accumulator value.
235 |
236 | The **reduce()** method is the most flexible of the map/filter/reduce triplet. In fact, it is possible to rewrite **map()** and **filter** using **reduce()**.
237 |
238 | ### Using reduce() to filter
239 |
240 | ```js
241 | const arr = [6, 3, 10, 1];
242 |
243 | const evenNumbers = arr.reduce((acc, elem) => {
244 | if (elem % 2 === 0) {
245 | acc.push(elem);
246 | }
247 | return acc;
248 | }, []);
249 |
250 | console.log(evenNumbers); // -> [6, 10]
251 | ```
252 |
253 | > _See this in action in this [JSBin](https://jsbin.com/pucaruv/edit?js,console)._
254 |
255 | In this example our accumulator is an (initially empty) array. We push elements (in this case integer numbers) in the accumulator only when they are divisible by 2.
256 |
257 | ### Using reduce() to map
258 |
259 | In this example an array of integer numbers is mapped to an array of their squares.
260 |
261 | ```js
262 | const arr = [6, 3, 10, 1];
263 |
264 | const squares = arr.reduce((acc, elem) => {
265 | acc.push(elem * elem);
266 | return acc;
267 | }, []);
268 |
269 | console.log(squares); // -> [36, 9, 100, 1]
270 | ```
271 |
272 | > _See this in action in this [JSBin](https://jsbin.com/gatayet/edit?js,console)._
273 |
274 | ## Using reduce() to 'group by'
275 |
276 | In this example our accumulator is not an array, but an (initially empty) object. It groups the array elements by gender.
277 |
278 | ```js
279 | const arr = [
280 | { gender: 'F', name: 'Joyce' },
281 | { gender: 'M', name: 'Jim' },
282 | { gender: 'F', name: 'Lucy' },
283 | { gender: 'F', name: 'Janet' },
284 | { gender: 'M', name: 'Jack' },
285 | { gender: 'M', name: 'Ferdinand' },
286 | ];
287 |
288 | const groupedNames = arr.reduce((acc, elem) => {
289 | if (acc[elem.gender]) {
290 | acc[elem.gender].push(elem);
291 | } else {
292 | acc[elem.gender] = [elem];
293 | }
294 | return acc;
295 | }, {});
296 |
297 | console.log(groupedNames);
298 | ```
299 |
300 | Result:
301 |
302 | ```js
303 | {
304 | F: [
305 | { gender: 'F', name: 'Joyce' },
306 | { gender: 'F', name: 'Lucy' },
307 | { gender: 'F', name: 'Janet' }
308 | ],
309 | M: [
310 | { gender: 'M', name: 'Jim' },
311 | { gender: 'M', name: 'Jack' },
312 | { gender: 'M', name: 'Ferdinand' }
313 | ]
314 | }
315 | ```
316 |
317 | > _See this in action in this [JSBin](https://jsbin.com/rufubu/edit?js,console)._
318 |
319 | ### Method chaining
320 |
321 | The methods **map()** and **filter()** each return a new array. This makes it possible to chain these methods and create a 'pipeline' of operations, to be applied in sequence. The **reduce** method can return anything, including an array. If a **reduce** method returns something other than an array it can only be located at the end of an array method chain. The same applied to **forEach()**: it doesn't return anything. Therefore, it can only be placed at the end of a chain.
322 |
323 | Let's take the last example, but now filtering out only those array elements for which the name starts with a 'J':
324 |
325 | ```js
326 | const arr = [
327 | { gender: 'F', name: 'Joyce' },
328 | { gender: 'M', name: 'Jim' },
329 | { gender: 'F', name: 'Lucy' },
330 | { gender: 'F', name: 'Janet' },
331 | { gender: 'M', name: 'Jack' },
332 | { gender: 'M', name: 'Ferdinand' },
333 | ];
334 |
335 | const groupedNames = arr
336 | .filter(elem => elem.name.startsWith('J'))
337 | .reduce((acc, elem) => {
338 | if (acc[elem.gender]) {
339 | acc[elem.gender].push(elem);
340 | } else {
341 | acc[elem.gender] = [elem];
342 | }
343 | return acc;
344 | }, {});
345 |
346 | console.log(groupedNames);
347 | ```
348 |
349 | Result:
350 |
351 | ```
352 | {
353 | F: [
354 | { gender: 'F', name: 'Joyce' },
355 | { gender: 'F', name: 'Janet' }
356 | ],
357 | M: [
358 | { gender: 'M', name: 'Jim' },
359 | { gender: 'M', name: 'Jack' }
360 | ],
361 | }
362 | ```
363 |
364 | > _See this in action in this [JSBin](https://jsbin.com/yovodag/edit?js,console)._
365 |
366 | ## In summary
367 |
368 | 
369 |
370 | Credit: http://www.globalnerdy.com/2016/06/23/map-filter-and-reduce-explained-using-emoji/
371 |
--------------------------------------------------------------------------------
/fundamentals/names_of_special_characters.md:
--------------------------------------------------------------------------------
1 |
2 | # Names of special characters
3 |
4 | In our coding sessions and homework we use all sorts of special characters, when you are new to coding or maybe even when you have been coding for a while, these names can be confusing. Here you can find a list of the most used special characters and their names.
5 |
6 | Do you think there is one (or more) missing? Make a PR with your additions 🙃!
7 |
8 |
9 | `(` Parentheses `)`
10 |
11 | `{` Braces, or Curly brackets `}`
12 |
13 | `[` Brackets, or square brackets `]`
14 |
15 | `<` Angle brackets `>`
16 |
17 | `'` Single quote `'`
18 |
19 | `"` Double quote `"`
20 |
21 | `` ` `` Back tick `` ` ``
22 |
23 | `/` Forward slash `/`
24 |
25 | `\` Back slash `\`
26 |
27 | `:` Colon `:`
28 |
29 | `;` Semicolon `;`
30 |
31 | `&` Ampersand `&`
32 |
33 | `*` Asterisk `*`
34 |
35 | `^` Caret or circumflex `^`
36 |
37 | `|` Vertical bar or pipe `|`
38 |
39 | `~` Tilde `~`
40 |
41 | `#` Hash or number sign `#`
42 |
43 | `_` Underscore `_`
44 |
45 | `-` Dash `-`
46 |
47 | See also the fundamentals page on [Operators](operators.md).
48 |
--------------------------------------------------------------------------------
/fundamentals/naming_conventions.md:
--------------------------------------------------------------------------------
1 | # Naming conventions
2 |
3 | ## Background
4 |
5 | In programming you will need to come up with appropriate names for your variables, functions and function parameters.
6 |
7 | > _The most important consideration in naming a variable is that the name fully and accurately describes the entity the variable represents. An effective technique for coming up with a good name is to state in words what the variable represents. Often that statement itself is the best variable name. It’s easy to read because it doesn’t contain cryptic abbreviations, and it’s unambiguous. Because it’s a full description of the
8 | entity, it won’t be confused with something else. And it’s easy to remember because the name is similar to the concept._
9 |
10 | > Source: [Code Complete 2, Steve McConnell](https://www.amazon.de/Code-Complete-Practical-Construction-Costruction/dp/0735619670)
11 |
12 | The names you choose are for the benefit of the human consumer of your code. Foremost this human consumer will be you yourself: when writing code carefully chosen names help you to stay focussed on the business problem you are trying to solve. When the need arises to revisit your code in the future, carefully chosen names will help you to reconstruct your state of mind at the time you originally wrote the code.
13 |
14 | In practice your code may need to be maintained by others, as you move on to other projects or jobs. For the developers doing maintenance, it is even more important to use carefully chosen names, as they do not have the benefit of having gone through your thought processes.
15 |
16 | The consumer least interested in the names you choose is the runtime environment (i.e. the JavaScript engine in your browser or Node). The runtime environment does not mind meaningless, one-letter variable names. In fact, a process called 'minification' is sometimes used to create a minified version of your JavaScript code for running in the browser, the purpose of which is to speed up fetching your code over the Internet.
17 |
18 | ## camelCase vs PascalCase vs snake_case vs kebab-case
19 |
20 | These terms are used to describe the conventions for the spelling of multi-word variable (and function) names.
21 |
22 | ### camelCase
23 |
24 | In JavaScript the convention is to spell the names of variables that contain data using _camelCase_, i.e. the first word in the variable name should start with a lower case letter and each subsequent word with an an upper case letter. It is called _camelCase_ because the hump in the middle of the word has some similarity with the hump of a camel.
25 |
26 | Example:
27 |
28 | ```js
29 | let myFavouriteMovies;
30 | ```
31 |
32 | ### PascalCase
33 |
34 | This casing is restricted in JavaScript to class names and constructor functions. This style of casing was customary in the Pascal programming language.
35 |
36 | Example:
37 |
38 | ```js
39 | class Movie {
40 | ...
41 | }
42 | ```
43 |
44 | ### snake_case
45 |
46 | This casing is not generally used in JavaScript except for naming global constants. In this case the variable name should be completely in upper case.
47 |
48 | ```js
49 | const MAX_AGE = 60;
50 | ```
51 |
52 | ### kebab-case
53 |
54 | This casing is used for class names in css and sometimes for filenames in JavaScript.
55 |
56 |
57 |
58 | ```css
59 | .page-title {
60 | color: #ff23be.
61 | }
62 | ```
63 |
64 | ```html
65 |
Beautiful Title
66 | ```
67 |
68 | ```js
69 | const fileName = 'movie-collection.js';
70 | ```
71 |
72 |
73 | ## Variable names for data
74 |
75 | Variables that contain data should be named using noun phrases, i.e. have a noun as its head word. The name should be in camelCase. Example:
76 |
77 | ```js
78 | let myFavouriteMovie;
79 | ```
80 |
81 | If the data consists of a single item the noun should be in singular form as in the example above. If the data consists of a collection, such as a JavaScript array or a JavaScript object that is used as a keyed collection then a plural form should be used:
82 |
83 | ```js
84 | let myFavouriteMovies;
85 | ```
86 |
87 | Sometimes a mass noun is used as head word instead of an explicit plural form for naming a collection. Examples of mass nouns are `data`, `input`, `money`.
88 |
89 | ## Function names
90 |
91 | Function names (exception: constructor functions, see below) should generally start with a verb to indicate the _action_ performed by the function. The name should be in camelCase. Example:
92 |
93 | ```js
94 | function fetchMovie() {
95 | ...
96 | }
97 | ```
98 |
99 | ## Constructor functions and class names
100 |
101 | The naming convention for constructor functions, i.e. functions that are used in conjunction with the `new` keyword, and ES6 class names is to use a noun phrase in PascalCase. Example:
102 |
103 | ```js
104 | class Movie {
105 | ...
106 | }
107 | ```
108 |
109 | ## Reserved keywords
110 |
111 | Certain names are reserved by JavaScript for its own use. You cannot use the names for your variable. For example, you can't name a variable `if`.
112 |
113 | For a complete list of reserved names, see the MDN page for [Keywords](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords).
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/fundamentals/objects.md:
--------------------------------------------------------------------------------
1 | # Objects
2 |
3 | Variables that are objects also contain a list of things, but instead of them being in some specific order, they can be assigned to words, called "keys". Instead of "elements" the things that are inside objects are called "properties".
4 |
5 |
6 | ```js
7 | let obj = {name: 'John', age: 24};
8 | ```
9 |
10 | This object has two properties: `name` and `age`. The "value" of the property `name` is the string `'John'`. The "value" of the property `age` is the number `24`.
11 |
12 | When accessing object properties, you can use the dot-notation: `obj.name` or the bracket-notation: `obj["name"]`. Note that the latter looks a lot like the way to access array elements. However, here what's inside the bracket (called "key" for objects, instead of "index") must be a string.
13 |
14 | ```js
15 | console.log(obj.name); // -> 'John'
16 | console.log(obj['name']); // -> 'John'
17 | ```
18 |
19 | Just like with arrays, you can also use a variable to access properties, as long as these variables are strings. In this case you cannot use the dot-notation!
20 |
21 | ```js
22 | const ageKey = 'age';
23 | console.log(obj[ageKey]); // -> 24
24 | ```
25 |
26 | Remember that there is a very big difference between `obj[name]` and `obj["name"]`.
27 |
28 | > Note:
29 | >
30 | > Thinking back of arrays, the length of an array can be retrieved by `arr.length`. So as mentioned before, arrays are just like other JavaScript objects. You could even write `arr['length']` to access the `length` property of the array. JavaScript will look: is what we put between brackets a number? Then it is an index and we'll look up the correct array element. If it's a string, it's a key and we will look up the corresponding property.
31 |
--------------------------------------------------------------------------------
/fundamentals/oop_classes.md:
--------------------------------------------------------------------------------
1 | # Object-Oriented Programming & Classes
2 |
3 | ### Object Literals and Imperative Programming
4 |
5 | In earlier JavaScript lectures we saw that we can create objects through object literals and use functions to access and manipulate their properties. A typical example is shown below, where we have defined an array of objects, in this case each representing the name of a month and its associated number of days.
6 |
7 | We're looping through the months and printing an informational message to the console for each month having 31 days.
8 |
9 | This style of programming is called Imperative Programming: in the code detail containing the `for` loop we instruct the computer _how to perform the task(s) at hand_.
10 |
11 | ```js
12 | const months = [
13 | { name: 'January', days: 31 },
14 | { name: 'February', days: 28 },
15 | { name: 'March', days: 31 },
16 | { name: 'April', days: 30 },
17 | { name: 'May', days: 31 },
18 | { name: 'June', days: 30 },
19 | { name: 'July', days: 31 },
20 | { name: 'August', days: 31 },
21 | { name: 'September', days: 30 },
22 | { name: 'October', days: 31 },
23 | { name: 'November', days: 30 },
24 | { name: 'December', days: 31 }
25 | ];
26 |
27 | for (const month of months) {
28 | if (month.days === 31) {
29 | console.log(`${month.name} has ${month.days} days.`);
30 | }
31 | }
32 | ```
33 |
34 | ## Functional Programming
35 |
36 | In the Functional Programming style (also referred to as Declarative Programming), we prefer to declare _what the computer should do_.
37 |
38 | In the next example we have used the `filter` method to extract a subset of months having 31 days, used the `map` method to create an informational string for each month and a `forEach` method to output those strings to the console.
39 |
40 | Put in other words, we state or **declare** that the computer should **filter** our array according to some predefined criterion, then **map** each filtered object to a string and print out each string to the console.
41 |
42 | > A prime example of a declarative language is SQL, which you will learn in the HYF Database module.
43 |
44 | In contrast to the Imperative Style we do not have to infer from looking at the code what is actually happening. Instead, the names of the functions and methods already indicate what it is we want to achieve.
45 |
46 | ```js
47 | const months = [
48 | { name: 'January', days: 31 },
49 | { name: 'February', days: 28 },
50 | { name: 'March', days: 31 },
51 | { name: 'April', days: 30 },
52 | { name: 'May', days: 31 },
53 | { name: 'June', days: 30 },
54 | { name: 'July', days: 31 },
55 | { name: 'August', days: 31 },
56 | { name: 'September', days: 30 },
57 | { name: 'October', days: 31 },
58 | { name: 'November', days: 30 },
59 | { name: 'December', days: 31 }
60 | ];
61 |
62 | months
63 | .filter(month => month.days === 31)
64 | .map(month => `${month.name} has ${month.days} days.`)
65 | .forEach(string => console.log(string));
66 | ```
67 |
68 | ### Constructor Functions (pre-ES6) and the `new` keyword
69 |
70 | In the example below, instead of using object literals, we use a function in conjunction with the `new` keyword to create objects. Such a function is called a **constructor** function, and, by convention, we start its name with an uppercase letter.
71 |
72 | When a function is called and preceded by the `new` keyword, something special happens. The JavaScript engine creates a new, empty object and assigns that object to the `this` variable.
73 |
74 | > The `this` variable is always present in JavaScript. Its value is dependent on the current execution context. Most of the time, the value of `this` is `undefined`. However, when calling a method on an object, the `this` variable holds a reference to the object it is called on. We can use the `this` variable inside the method implementation to get at other properties and methods within the object.
75 |
76 | We can now add properties to the new object through the `this` variable, as shown below.
77 |
78 | When the constructor function finishes, it returns the newly constructed object as its return value.
79 |
80 | ```js
81 | function Month(name, days) {
82 | this.name = name;
83 | this.days = days;
84 | }
85 |
86 | const months = [
87 | new Month('January', 31),
88 | new Month('February', 28),
89 | new Month('March', 31),
90 | new Month('April', 30),
91 | new Month('May', 31),
92 | new Month('June', 30),
93 | new Month('July', 31),
94 | new Month('August', 31),
95 | new Month('September', 30),
96 | new Month('October', 31),
97 | new Month('November', 30),
98 | new Month('December', 31)
99 | ];
100 |
101 | months
102 | .filter(month => month.days === 31)
103 | .map(month => `${month.name} has ${month.days} days.`)
104 | .forEach(string => console.log(string));
105 | ```
106 |
107 | - [Understanding JavaScript Function Invocation and "this"](http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/), by Yehuda Katz.
108 |
109 | - StackOverflow: [What is the 'new' keyword in JavaScript?](https://stackoverflow.com/questions/1646698/what-is-the-new-keyword-in-javascript)
110 |
111 | ### Introducing Object-Oriented Programming
112 |
113 | In the preceding example, there was not much to be gained from using a constructor function in conjunction with the `new` keyword, as compared to just using object literals. The advantages become more clear when we start to add **methods** to the object. Methods are just plain JavaScript functions that you call on an object, using dot notation. In the code snippet below, we have defined a couple of functions and assigned them to object properties through the `this` variable in the constructor function. This makes these functions into methods.
114 |
115 | ```js
116 | function Month(name, days) {
117 | this.name = name;
118 | this.days = days;
119 |
120 | this.hasDays = function (days) {
121 | return this.days === days;
122 | };
123 |
124 | this.isLongMonth = function () {
125 | return this.hasDays(31);
126 | };
127 |
128 | this.toString = function () {
129 | return `${this.name} has ${this.days} days.`;
130 | };
131 |
132 | this.toConsole = function () {
133 | console.log(this.toString());
134 | };
135 | }
136 |
137 | const months = [
138 | new Month('January', 31),
139 | new Month('February', 28),
140 | new Month('March', 31),
141 | new Month('April', 30),
142 | new Month('May', 31),
143 | new Month('June', 30),
144 | new Month('July', 31),
145 | new Month('August', 31),
146 | new Month('September', 30),
147 | new Month('October', 31),
148 | new Month('November', 30),
149 | new Month('December', 31)
150 | ];
151 |
152 | months
153 | .filter(month => month.isLongMonth())
154 | .forEach(month => month.toConsole());
155 | ```
156 |
157 | We can now call these methods using dot notation, as in:
158 |
159 | ```js
160 | month.isLongMonth()
161 | month.toConsole()
162 | ```
163 |
164 | We have already seen this notation when we used, for instance, `map` and `filter`.
165 |
166 | When we add methods to an object to operate on data contained in the object, we have created a more or less self-contained object. The object knows how to operate its data and external code need not know anything about its internals. This concept is known as Object-Oriented Programming. It is the default style of programming in object-oriented languages such as Java, C# and C++. In JavaScript it is optional. In the HYF React module, ES6 classes are used extensively.
167 |
168 | ### Prototypes
169 |
170 | The code from the previous example has a significant inefficiency: each object get its own copy of the methods (`hasDays` etc). This takes up unnecessary memory. It would be far better if the objects could share a common set of methods. This is where JavaScript's concept of a `prototype` comes in.
171 |
172 | Each JavaScript function has a `prototype` property that points to an, initially empty, prototype object. It only comes into play when using that function as a **constructor** function. We can assign functions to this prototype which are shared by all objects we create through calling the constructor function in combination with the `new` keyword.
173 |
174 | ```js
175 | function Month(name, days) {
176 | this.name = name;
177 | this.days = days;
178 | }
179 |
180 | Month.prototype.hasDays = function (days) {
181 | return this.days === days;
182 | };
183 |
184 | Month.prototype.isLongMonth = function () {
185 | return this.hasDays(31);
186 | };
187 |
188 | Month.prototype.toString = function () {
189 | return `${this.name} has ${this.days} days.`;
190 | };
191 |
192 | Month.prototype.toConsole = function () {
193 | console.log(this.toString());
194 | }
195 |
196 | const months = [
197 | new Month('January', 31),
198 | new Month('February', 28),
199 | new Month('March', 31),
200 | new Month('April', 30),
201 | new Month('May', 31),
202 | new Month('June', 30),
203 | new Month('July', 31),
204 | new Month('August', 31),
205 | new Month('September', 30),
206 | new Month('October', 31),
207 | new Month('November', 30),
208 | new Month('December', 31)
209 | ];
210 |
211 | months
212 | .filter(month => month.isLongMonth())
213 | .forEach(month => month.toConsole());
214 | ```
215 |
216 |
217 | 
218 | Figure 1: All objects instantiated with the Model constructor function share a common prototype.
219 |
220 | ### Prototype vs \_\_prototype\_\_
221 |
222 | The above diagram depicts how this sharing works out.
223 |
224 | The `prototype` property exists on all functions but is only relevant when that function is used as a **constructor function**. By assigning methods to the `prototype` property you are basically defining a ‘prototype’ object that will be shared by all objects created through the constructor function when called in conjunction with the `new` keyword.
225 |
226 | In contrast to `prototype`, the `__proto__` property (in documentation sometimes denoted as `[[proto]]`) is a property that exist on objects created through the constructor function. This `__proto__` property points to the shared ‘prototype’ object, as defined on the constructor function’s `prototype` property.
227 |
228 | The prototype object itself also has a `__proto__` property. In most cases this property points to the prototype of the standard JavaScript `Object` prototype. This is because, ultimately, all objects in JavaScript are prototype-linked to the `Object` prototype. In OOP terms one would say that all JavaScript objects ultimately derive from `Object`.
229 |
230 | There is no `__proto__` property on the `Object` prototype itself. This is where the prototype chain ends.
231 |
232 | When you call a method on an object that does not exist on the object itself, the JavaScript engine will 'walk' down the prototype chain until it finds the requested method _or_ until it reaches the end of the chain.
233 |
234 | If the method is found, JavaScript calls the method, setting its `this` value to the object the method was called on. This happens behind the scenes without requiring intervention from the programmer.
235 |
236 | If the method was not found by walking the prototype chain, a run-time error is produced, e.g:
237 |
238 | ```js
239 | myObj.someNonExistingMethod();
240 |
241 | ```
242 |
243 | ```
244 | myObj.someNonExistingMethod();
245 | ^
246 |
247 | TypeError: myObj.someNonExistingMethod is not a function
248 | ```
249 |
250 | ### ES6 Classes
251 |
252 | In ES6 a new way of defining objects and its methods was introduced. It uses the same `prototype` mechanism behind the scenes, but its syntax is closer to that of other object-oriented languages, such as Java, etc. Because it is only new syntax, hiding the intricacies of the `prototype`, it is often designated as 'syntactic sugaring'.
253 |
254 | In ES6 classes we use the `class` keyword to define a class. The `constructor` method takes the place of the constructor function of the previous examples.
255 |
256 | We define methods by creating functions inside the class body, however without the `function` keyword. As previously, the `this` keyword refers to the object that a method is called upon.
257 |
258 | ```js
259 | class Month {
260 | constructor(name, days) {
261 | this.name = name;
262 | this.days = days;
263 | }
264 |
265 | hasDays(days) {
266 | return this.days === days;
267 | }
268 |
269 | isLongMonth() {
270 | return this.hasDays(31);
271 | }
272 |
273 | toString() {
274 | return `${this.name} has ${this.days} days.`;
275 | }
276 |
277 | toConsole() {
278 | console.log(this.toString());
279 | }
280 | }
281 |
282 | const months = [
283 | new Month('January', 31),
284 | new Month('February', 28),
285 | new Month('March', 31),
286 | new Month('April', 30),
287 | new Month('May', 31),
288 | new Month('June', 30),
289 | new Month('July', 31),
290 | new Month('August', 31),
291 | new Month('September', 30),
292 | new Month('October', 31),
293 | new Month('November', 30),
294 | new Month('December', 31)
295 | ];
296 |
297 | months
298 | .filter(month => month.isLongMonth())
299 | .forEach(month => month.toConsole());
300 | ```
301 |
302 |
303 | ### Bonus: Array.prototype.map & Array.prototype.filter Implementations
304 |
305 | Now that we know a bit more about objects, prototypes and the `this` variable, it might be useful to revisit the `map` and `filter` methods we used before and examine how they might be implemented internally.
306 |
307 | In the examples below, we have defined alternative implementations for `map` and `filter` and named them `myMap` and `myFilter`. If we run this code we are actually adding these methods to the existing `Array` constructor function (in general, it is a bad idea to modify standard JavaScript objects, but we use it here for illustrative purposes).
308 |
309 | The `this` variable inside the method implementations refer to the array (which is technically an object: `typeof arr === 'object'`) on which the method is called.
310 |
311 | As you can see, both methods use a `for` loop internally, saving us the trouble of writing a `for` loop ourselves. Both methods call a callback that was passed as a parameter. The callback, in its turn, is called for every loop iteration with three parameters, viz:
312 |
313 | 1. The current array element
314 | 2. The current loop index value
315 | 3. The complete array itself
316 |
317 | For the `map` method, the value that we return from our callback is pushed onto a new, initially empty array.
318 |
319 | For the `filter` method, the current element is pushed unmodified to a new, initially empty array if, and only if our callback returns a 'truthy' value.
320 |
321 | Finally, both methods return the newly constructed array as their return value.
322 |
323 | ```js
324 | Array.prototype.myMap = function (callback) {
325 | const arr = [];
326 | for (let i = 0; i < this.length; i++) {
327 | arr.push(callback(this[i], i, this));
328 | }
329 | return arr;
330 | };
331 | ```
332 |
333 |
334 | ```js
335 | Array.prototype.myFilter = function (callback) {
336 | const arr = [];
337 | for (let i = 0; i < this.length; i++) {
338 | if (callback(this[i], i, this)) {
339 | arr.push(this[i]);
340 | }
341 | }
342 | return arr;
343 | };
344 | ```
345 |
346 |
--------------------------------------------------------------------------------
/fundamentals/operators.md:
--------------------------------------------------------------------------------
1 | # Operators
2 |
3 | ## Comparison operators
4 |
5 | >Note the two different uses of the equals sign:
6 | >A single equals sign (=) is used to assign a value to a variable.
7 | A triple equals sign (===) is used to compare two values (see Equality Operators).
8 |
9 | ### Equality operators
10 |
11 | * Equality `==`
12 | * Inequality `!=`
13 | * Identity / strict equality `===` (preferred)
14 | * Non-identity / strict inequality `!==` (preferred)
15 |
16 | How does this work in practice?
17 |
18 | ```js
19 | 1 == 1 // -> true
20 | 7 == '7' // -> true
21 | 1 != 2 // -> true
22 | 5 === 5 // -> true
23 | 9 === '9' // -> false
24 | 3 !== 3 // -> false
25 | 3 !== '3' // -> true
26 | ```
27 |
28 | > why does `7 == '7'` returns true and `9 === '9'` returns false?
29 |
30 | We strongly recommend that you always use the strict form when comparing for equality (`===`) or inequality (`!==`). Use the non-strict forms only when there is a compelling reason to do so (you will be hard pressed to find such a reason).
31 |
32 | ### Relational operators
33 |
34 | * Greater than operator `>`
35 | * Greater than or equal operator `>=`
36 | * Less than operator `<`
37 | * Less than or equal operator `<=`
38 |
39 | ```js
40 | 4 > 3 // -> true
41 | 3 >= 3 // -> true
42 | 13 < 12 // -> false
43 | 3 <= 4 // -> true
44 | ```
45 |
46 | More about [comparison operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
47 |
48 | ## Arithmetic operators
49 |
50 | * Addition `+`
51 | * Subtraction `-`
52 | * Multiplication `*`
53 | * Division `/`
54 | * Remainder (sometimes called modulo) `%`
55 | Returns the remainder left over after you've shared the left number out into a number of integer portions equal to the right number.
56 |
57 | ```js
58 | 8 + 9 // -> 17, adds two numbers together.
59 | 20 - 12 // -> 8, subtracts the right number from the left.
60 | 3 * 4 // -> 12, multiplies two numbers together.
61 | 10 / 5 // -> 2, divides the left number by the right.
62 | 8 % 3 /// -> 2, as three goes into 8 twice, leaving 2 left over.
63 | ```
64 |
65 | More about [Arithmetic operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#.25_.28Modulus.29)
66 |
67 | ## Logical operators
68 |
69 | * AND `&&`
70 | * OR `||`
71 |
72 | ```js
73 | true && false //-> false
74 | false && true //-> false
75 | false || true //-> true
76 | true || false //-> true
77 | ```
78 |
79 | Given that x = 6 and y = 3
80 | ```js
81 | x < 10 && y > 1 // -> true
82 | x === 5 || y === 5 // -> false
83 | x !== y // -> true
84 | ```
85 |
86 | Logical NOT
87 |
88 | * NOT `!`
89 |
90 | ```js
91 | true === !false
92 | false === !true
93 | ```
94 |
95 | More about [logical operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_Operators)
96 |
97 | ### typeof operator
98 |
99 | To get the type of a value assigned to a variable, use the following code:
100 |
101 | ```js
102 | let bar = 42;
103 | typeof bar //-> 'number'
104 | typeof typeof bar; //-> 'string'
105 | ```
106 |
107 | So the data type of what `typeof` returns is always a string, bar on the other hand is still a number.
108 |
109 | ## Assignment operators
110 |
111 | In addition to the simple assignment operator `=` there are also compound assignment operators such as `+=`. The following two assignments are equivalent:
112 |
113 | ```js
114 | x += 1;
115 | x = x + 1;
116 | ```
117 |
118 | |Operator| Example| Same As|
119 | |:------:|:--------:|:-------:|
120 | |`=` | `x = y` | `x = y`|
121 | |`+=`| `x += y` | `x = x + y`|
122 | |`-=`| `x -= y` | `x = x - y`|
123 | |`*=`| `x *= y` | `x = x * y`|
124 | |`/=`| `x /= y` | `x = x / y`|
125 | |`%=`| `x %= y` | `x = x % y`|
126 |
127 | Also check out [special characters and their names](names_of_special_characters.md)
128 |
--------------------------------------------------------------------------------
/fundamentals/promises.md:
--------------------------------------------------------------------------------
1 | # Promises
2 |
3 |
4 | ## What is a promise?
5 |
6 | Why is a JavaScript ES6 `promise` called a 'promise'? Here is a snippet from the *Oxford Dictionary of English* definition of 'promise':
7 |
8 | > **promise** |ˈprɒmɪs|
9 | noun
10 | 1 a declaration or assurance that one will do something or that a particular thing will happen
11 |
12 | This pretty well sums up what a promise means in JavaScript: something that will be delivered in the future (if and when the promise is *fulfilled*).
13 |
14 | Traditionally, *callbacks* are used as a way to receive the data that is delivered asynchronously (meaning that the data is not likely to be available at the time it is requested but can be expected some time later). Using callbacks can quickly become unwieldy when dealing with many asynchronous events (e.g., ajax calls), especially when they depend on each other (google for *callback hell*).
15 |
16 | JavaScript ES6 introduces promises as a better alternative for callbacks when dealing with asynchronous events.
17 |
18 | We can state a number of simple facts about ES6 promises:
19 |
20 | - A promise is a JavaScript object (`typeof somePromise === 'object'`) that serves as a placeholder for a (future) value.
21 | - Because a promise is an ordinary JavaScript object you can pass it around as an argument to a function, return it from a function, assign it to a variable, push it to an array, etc.
22 | - You can receive the 'promised' value by calling the `.then()` method of the promise, passing it a function that will receive that value as its argument as soon as it is available.
23 | - You can create a promise by calling the ES6 `Promise` constructor function with `new` (see Listing 1 below), then call `resolve()` when results are ready or `reject()` on detecting an error.
24 | - Sometimes you can get a ready-made promise by calling an appropriate API or library function, like the `fetch()` Web API function in Listing 1.
25 | - Internally, a promise can be in one of three states:
26 | - **pending**: the asynchronous result is still awaiting delivery
27 | - **fulfilled**: the asynchronous result has been delivered and is available (`resolve()` was called)
28 | - **rejected**: an error was encountered: the promise could not be fulfilled (`reject()` was called)
29 | - A promise that is no longer pending because it was either fulfilled or rejected is said to be _settled_.
30 | - A promise that is _settled_ has reached its final state. Its state and value can no longer be changed. It has become _immutable_. Subsequently calling `resolve()` or `reject()` does no longer affect the outcome of the promise.
31 |
32 | ## Example code
33 |
34 | Listing 1 shows an example based on an asynchronous XMLHttpRequest that we will use throughout the rest of this discussion.
35 |
36 | ```js
37 | 'use strict';
38 |
39 | function fetchJSON(url) {
40 | return new Promise((resolve, reject) => {
41 | const xhr = new XMLHttpRequest();
42 | xhr.open('GET', url);
43 | xhr.responseType = 'json';
44 | xhr.onreadystatechange = () => {
45 | if (xhr.readyState === 4) {
46 | if (xhr.status < 400) {
47 | resolve(xhr.response);
48 | } else {
49 | reject(new Error(xhr.statusText));
50 | }
51 | }
52 | };
53 | xhr.send();
54 | });
55 | }
56 |
57 | // alternative:
58 | // const fetchJSON = url => fetch(url).then(res => res.json());
59 |
60 | const url = 'http://api.nobelprize.org/v1/laureate.json?gender=female';
61 |
62 | fetchJSON(url)
63 | .then(data => renderData(data))
64 | .catch(err => renderError(err));
65 |
66 | function renderData(data) {
67 | console.log(data);
68 | }
69 |
70 | function renderError(err) {
71 | console.error(err.message);
72 | }
73 | ```
74 |
75 | Listing 1. Asynchronous `XMLHttpRequest` (and `fetch` alternative) using a promise.
76 |
77 | The `fetchJSON()` function in Listing 1 returns a `promise` that resolves to a value converted from JSON data received from a remote API end point. The alternative version of `fetchJSON()` (commented out here) uses a more modern browser function that natively returns a promise.
78 |
79 |
80 | ## The .then() method
81 |
82 | A promise exposes a `.then()` method through which you can obtain its fulfilled value or an error value in the case the promise was rejected:
83 |
84 | ```js
85 | somePromise.then(onFulfilled, onRejected);
86 | ```
87 |
88 | The `.then()` method takes as its parameters two **optional** functions, the first one dealing with the 'happy' scenario (the promise is fulfilled) and the second one dealing with the error case (the promise is rejected). If you are only interested in the success case you can leave out the second parameter:
89 |
90 | ```js
91 | somePromise.then(data => {
92 | // ...
93 | });
94 | ```
95 |
96 | If you are only interested in the error case, you can pass `null` for the first argument:
97 |
98 | ```js
99 | somePromise.then(null, err => {
100 | //...
101 | });
102 | ```
103 |
104 | or you can use another method available on a promise, `.catch()`, which is just a shorthand for calling `then()` with `null` as its first argument:
105 |
106 | ```js
107 | somePromise
108 | .then(data => {
109 | // ...
110 | })
111 | .catch(err => {
112 | // ...
113 | });
114 | ```
115 |
116 | Note that the `onFulfilled` and `onRejected` handler functions always execute asynchronously. When the promise is settled, the `onFulFilled` or `onRejected` handler is placed on the event/callback queue. They execute when the currently executing JavaScript code runs to completion, causing the [call stack](./event_loop.md#call-stack) to become empty and enabling the event loop to process the next event from the queue. This holds true even if the promise is immediately fulfilled or rejected, as in this example:
117 |
118 | ```js
119 | Promise.resolve(42)
120 | .then(data => console.log(data));
121 |
122 | console.log('after promise');
123 |
124 | // console output:
125 | // after promise
126 | // 42
127 | ```
128 |
129 | This example also shows how you can create a promise that is immediately resolved. There is no need to use `new` or to pass a `(resolve, reject) => {}` function to the `Promise` constructor. Similarly you can create a promise that is immediately rejected:
130 |
131 | ```js
132 | Promise.reject(new Error('oops'))
133 | .catch(err => console.log(err.message));
134 |
135 | console.log('after promise');
136 |
137 | // console output:
138 | // after promise
139 | // oops
140 | ```
141 |
142 | ## Promise chaining
143 |
144 | It is important to understand that the `.then()` method returns a new promise that resolves to the return value of `onFulfilled` (if specified) in case of the 'happy' scenario or the return value of `onRejected()` (if specified) in case of an error. If the return value of these functions is a plain JavaScript value, the new promise is immediately fulfilled with that value. If the return value is yet another promise then the outcome is determined by the inner promise, once settled. If the function does not return a value, the new promise is immediately fulfilled with the value `undefined`.
145 |
146 | Because `.then()` (and `.catch`) return new promises, you can chain them together such that your code can be read as: do *this*, then do *that* and then *that*, etc.:
147 |
148 | ```js
149 | function fetchAndRender(url, otherUrl) {
150 | fetchJSON(url)
151 | .then(data => {
152 | renderData(data);
153 | return fetchJSON(otherUrl);
154 | })
155 | .then(otherData => {
156 | renderOtherData(otherData);
157 | })
158 | .catch(err => {
159 | renderError(err);
160 | });
161 | }
162 |
163 | fetchAndRender();
164 | ```
165 |
166 | Listing 2. Chaining of `then` and `catch`
167 |
168 | Let's examine Listing 2 in a bit more detail. There two calls to `fetchJSON()`. Errors are handled in one place, by means of the `.catch()` method that terminates the promise "chain".
169 |
170 | If you embed another promise inside the function that you pass to the `.then()` method (in Listing 2 this is done in the first `.then()`) you should return that promise as the function's return value. If you don't return the promise, there is no way for the `.catch()` at the end of the chain to "see" a `reject()` of the inner promise, leaving the rejection unhandled.
171 |
172 | In case a promise in the chain is rejected due to some error, the promise chain will be traversed until an `onRejected` handler (e.g., in a terminating `.catch()` method) is found. All intermediate `onFulfilled` handlers (e.g. `.then()`) will be skipped.
173 |
174 | Handling errors at the end of a promise chain is a major advantage over the repetition of error handling code in the case of callbacks.
175 |
176 | Note however that a `.catch()` method does not necessarily have to be the last method in the chain. It can be used to handle errors midway. As mentioned previously, the `.catch()` method returns a new promise which can be used to provide some "fallback" value in case of errors.
177 |
178 | In the example below a promise is created that is immediately rejected. The promise is subsequently "consumed" twice.
179 |
180 | 1. In the first case ('consumer 1'), the rejection is caught by a `.catch()` method and the rejection value `'bad'` is printed on the console.
181 |
182 | 2. In the second case ('consumer 2'), the rejection is also caught by a `.catch()` method, but now the catch handler completely ignores the rejection value and just returns the fallback value `'good.`. This becomes the fulfilled value of the promise returned by `.catch()`. The next `.then()` in the chain, completely oblivious that an error ever occurred, now prints the fulfilled value `'good'` on the console.
183 |
184 | ```js
185 | const promise = Promise.reject('bad');
186 |
187 | // consumer 1
188 | promise
189 | .catch(console.log); // -> "bad"
190 |
191 | // consumer 2
192 | promise
193 | .catch(() => 'good')
194 | .then(console.log); // -> "good"
195 | ```
196 |
197 | ## Promise.all()
198 |
199 | There may be situations where you want to execute multiple promises in parallel and wait until all promises are resolved. Of course, these promises must not be interdependent (i.e. a promise must not depend on the result of another promise running in parallel). The `Promise.all()` method accepts an array (or more precisely, an _iterable_) of promises. It return a new promise that is resolved when all promises in the array are resolved, or rejected as soon as one of the promises in the array is rejected.
200 |
201 | The fulfilled value of the new promise is an array of fulfilled values of the individual promises passed to `Promise.all()`, in the same order.
202 |
203 | More details on MDN: [Promise.all()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)
204 |
205 | ## Additional resources
206 |
207 | Our previous students also enjoyed learning about promises at:
208 |
209 | In text:
210 |
211 | - http://javascript.info/promise-basics
212 | - https://blog.cloudboost.io/explaining-basic-javascript-promises-in-jip-en-janneketaal-c98763c0abd6
213 | - https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-promise-27fc71e77261
214 |
215 | Video: The net Ninja: https://www.youtube.com/watch?v=yswb4SkDoj0
216 |
217 | MDN:
218 |
219 | - [MDN - Promise definition](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
220 | - [MDN - Using Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises)
221 | - [Promises/A+ specification](https://promisesaplus.com/)
222 |
--------------------------------------------------------------------------------
/fundamentals/scope.md:
--------------------------------------------------------------------------------
1 | # Scope
2 |
3 | ## What is scope?
4 |
5 | Definition from [Dictionary.com](http://www.dictionary.com/browse/scope):
6 |
7 | > noun
8 | 1\. extent or range of view, outlook, application, operation, effectiveness, etc.:
9 |
10 | If you imagine yourself as the computer that is executing your JavaScript code, you can think of scope as meaning:
11 |
12 | > what you can see from where you are
13 |
14 | In this case the 'things' that you are looking for are variables and functions. When we say, "What's in scope?", we mean "Which variables and functions can be accessed from the current point of execution in your code?" As it happens, in JavaScript there are three types of scope to consider.
15 |
16 | ## Global scope
17 |
18 | Variables and functions defined at global scope are visible from any point of execution in your code. Sometimes that's a good thing (or even essential), but in general you must avoid creating variables and functions in global scope unless you have specific reasons to do so.
19 |
20 | Consider the example below:
21 |
22 | ```js
23 | a = 'Hello'; // don't do this
24 | console.log(a);
25 | ```
26 |
27 | In this example we have assigned the value `'Hello'` to a variable that we forgot to declare (we forgot to use `let`, `const` or `var`). The JavaScript engine tries to be helpful and defines a variable `a` for us in **global** scope. More recently, the JavaScript community considered this friendliness to be a mistake and with ES5 introduced `strict` mode: place the string `'use strict';` at the top of your file. This now causes our code to fail with a run-time error when forgetting to 'declare' our variables.
28 |
29 | ```js
30 | 'use strict';
31 | a = 'Hello'; // produces: ReferenceError: a is not defined
32 | console.log(a);
33 | ```
34 |
35 | You can correct this by declaring your variable with `let`, `const` or `var`:
36 |
37 | ```js
38 | 'use strict';
39 | var a = 'Hello';
40 | console.log(a);
41 | ```
42 |
43 | This still puts the variable `a` into the global scope. So why is global scope a problem? Because you cannot be sure that the variable names you choose do not conflict with names already present in global scope (global scope is a busy place).
44 |
45 | It is best to apply the principle of 'need to know'. Only expose your variables to other parts in the JavaScript ecosystem that need to know about them. This is where local scope and block scope come in.
46 |
47 | ## Local scope
48 |
49 | When you declare a function in JavaScript the function body represents a new, local scope, distinct from global scope. Variables defined in the function body are visible in that function body only: from the outside, you can't look in.
50 |
51 | ```js
52 | 'use strict';
53 |
54 | function myFunction() {
55 | const a = 'Hello';
56 | console.log(a);
57 | }
58 |
59 | myFunction();
60 |
61 | // console.log(a); <= this would produce: ReferenceError: a is not defined
62 | ```
63 |
64 | But from the inside you can look out. In the example below the variable `a` is visible from inside the function body.
65 |
66 | ```js
67 | 'use strict';
68 |
69 | const a = 'Hello';
70 |
71 | function myFunction() {
72 | const b = ', world';
73 | console.log(a + b);
74 | }
75 |
76 | myFunction();
77 | ```
78 |
79 | You might think that the variable `a` is in global scope. Actually, variables declared with either `let` or `const` have block scope, as will be discussed next. Note however that the function `myFunction` still resides in global scope. There is a way to get `myFunction` out of the global scope by using, what is called, an **IIFE** to create a **local scope** (or, with ES6, by placing the function definition in a block to create a **block scope**). See further down below.
80 |
81 | ## Block scope
82 |
83 | The keywords `let` and `const` were introduced in ES6 as alternatives to the existing `var` keyword. We recommend that you use these newer keywords instead of `var`. They adhere to the rules for **block scope**, whereas `var` is completely oblivious of the concept.
84 |
85 | A new block scope (sometimes called _lexical_ scope) is created whenever you create a block of code inside a pair of curly braces. (Exception: the curly braces used to enclose the body of a function definition do not create a block scope. Instead, a **local scope** is created as discussed in the previous section.)
86 |
87 | Variables defined with `let` and `const` at the file level (i.e., not inside a function or a block) are considered to be in a file-level block scope ('script' scope). That's why the variable `a` in the previous code snippet is not in global scope. Had we replaced `const a` with `var a` then variable `a` _would be_ in global scope.
88 |
89 | ## Scope Example
90 |
91 | In the figure below we show an example bringing all scope types together. The code fragment on the right-hand side is executed by means of a `