|
| 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 | + "ecmaFeatures": { |
| 102 | + "jsx": true |
| 103 | + }, |
| 104 | + "sourceType": "module" |
| 105 | + }, |
| 106 | + "extends": [ |
| 107 | + "eslint:recommended" |
| 108 | + ], |
| 109 | + "rules": { |
| 110 | + "no-const-assign": "warn", |
| 111 | + "no-this-before-super": "warn", |
| 112 | + "no-undef": "warn", |
| 113 | + "no-unreachable": "warn", |
| 114 | + "no-unused-vars": "warn", |
| 115 | + "constructor-super": "warn", |
| 116 | + "valid-typeof": "warn", |
| 117 | + "no-var": "warn", |
| 118 | + "prefer-const": "warn", |
| 119 | + "no-multiple-empty-lines": "warn", |
| 120 | + "eol-last": [ |
| 121 | + "error", |
| 122 | + "always" |
| 123 | + ], |
| 124 | + "no-console": "off", |
| 125 | + "camelcase": "warn", |
| 126 | + "eqeqeq": [ |
| 127 | + "error", |
| 128 | + "always", |
| 129 | + { |
| 130 | + "null": "ignore" |
| 131 | + } |
| 132 | + ], |
| 133 | + "semi": [ |
| 134 | + "warn", |
| 135 | + "always" |
| 136 | + ] |
| 137 | + } |
| 138 | +} |
| 139 | +``` |
| 140 | + |
| 141 | + |
| 142 | +## Example of well-formatted code |
| 143 | + |
| 144 | +(With the help of the VSCode formatter and ESLint.) |
| 145 | + |
| 146 | +```js |
| 147 | +'use strict'; |
| 148 | + |
| 149 | +const board = [ |
| 150 | + ['T', 'T', '.', 'F'], |
| 151 | + ['T', '.', '.', '.'], |
| 152 | + ['.', '.', '.', '.'], |
| 153 | + ['R', '.', '.', 'W'] |
| 154 | +]; |
| 155 | + |
| 156 | +const robot = { |
| 157 | + x: 0, |
| 158 | + y: 0, |
| 159 | + dir: 'up', |
| 160 | +}; |
| 161 | + |
| 162 | +let flagReached = false; |
| 163 | +let moves = 0; |
| 164 | + |
| 165 | +board.reverse(); |
| 166 | + |
| 167 | +const trailIndicators = { |
| 168 | + left: '←', |
| 169 | + right: '→', |
| 170 | + up: '↑', |
| 171 | + down: '↓' |
| 172 | +}; |
| 173 | + |
| 174 | +function render() { |
| 175 | + console.log('\n ' + moves + ':'); |
| 176 | + for (let row = board.length - 1; row >= 0; row--) { |
| 177 | + const cells = board[row]; |
| 178 | + let line = ''; |
| 179 | + for (let col = 0; col < cells.length; col++) { |
| 180 | + line += ' ' + cells[col] + ' '; |
| 181 | + } |
| 182 | + console.log(line); |
| 183 | + } |
| 184 | + if (flagReached) { |
| 185 | + console.log('\nHurray! Flag reached in ' + moves + ' steps!'); |
| 186 | + } |
| 187 | +} |
| 188 | + |
| 189 | +function move() { |
| 190 | + let x = robot.x; |
| 191 | + let y = robot.y; |
| 192 | + |
| 193 | + switch (robot.dir) { |
| 194 | + case 'up': |
| 195 | + y = y < board.length - 1 ? y + 1 : y; |
| 196 | + break; |
| 197 | + case 'down': |
| 198 | + y = y > 0 ? y - 1 : y; |
| 199 | + break; |
| 200 | + case 'left': |
| 201 | + x = x > 0 ? x - 1 : x; |
| 202 | + break; |
| 203 | + case 'right': |
| 204 | + x = x < board[y].length - 1 ? x + 1 : x; |
| 205 | + break; |
| 206 | + } |
| 207 | + |
| 208 | + const cellContents = board[y][x]; |
| 209 | + |
| 210 | + if (cellContents === '.' || cellContents === 'F') { |
| 211 | + board[robot.y][robot.x] = trailIndicators[robot.dir]; |
| 212 | + robot.x = x; |
| 213 | + robot.y = y; |
| 214 | + board[y][x] = 'R'; |
| 215 | + if (cellContents === 'F') { |
| 216 | + flagReached = true; |
| 217 | + } |
| 218 | + } |
| 219 | + |
| 220 | + moves += 1; |
| 221 | + render(); |
| 222 | +} |
| 223 | + |
| 224 | +function turn(turnDirection) { |
| 225 | + if (turnDirection !== 'left' && turnDirection !== 'right') { |
| 226 | + console.log('ignoring invalid turn', turnDirection); |
| 227 | + } |
| 228 | + switch (robot.dir) { |
| 229 | + case 'up': |
| 230 | + robot.dir = turnDirection === 'left' ? 'left' : 'right'; |
| 231 | + break; |
| 232 | + case 'down': |
| 233 | + robot.dir = turnDirection === 'left' ? 'right' : 'left'; |
| 234 | + break; |
| 235 | + case 'left': |
| 236 | + robot.dir = turnDirection === 'left' ? 'down' : 'up'; |
| 237 | + break; |
| 238 | + case 'right': |
| 239 | + robot.dir = turnDirection === 'left' ? 'up' : 'down'; |
| 240 | + break; |
| 241 | + } |
| 242 | +} |
| 243 | + |
| 244 | +render(); |
| 245 | + |
| 246 | +// start of robot game instructions |
| 247 | +move(); |
| 248 | +turn('right'); |
| 249 | +move(); |
| 250 | +move(); |
| 251 | +move(); |
| 252 | +turn('left'); |
| 253 | +move(); |
| 254 | +move(); |
| 255 | +// end of robot game instructions |
| 256 | +``` |
| 257 | + |
0 commit comments