|
|
|
\[\[_TOC_\]\]
|
|
|
|
|
|
|
|
# Purpose
|
|
|
|
|
|
|
|
This documents aims at defining standard coding rules for all Javascript code in the application. It is based on \[Mozilla guidelines for Javascript\](<https://developer.mozilla.org/en-US/docs/MDN/Guidelines/Code_guidelines/JavaScript>).
|
|
|
|
|
|
|
|
## General guidelines
|
|
|
|
|
|
|
|
### Use expanded syntax
|
|
|
|
|
|
|
|
For JavaScript we use expanded syntax, with each line of JS on a new line, the opening brace of a block on the same line as its associated statement, and the closing brace on a new line.
|
|
|
|
|
|
|
|
Do this :
|
|
|
|
|
|
|
|
`function myFunc() {`
|
|
|
|
|
|
|
|
`console.log('Hello!');`
|
|
|
|
|
|
|
|
`};`
|
|
|
|
|
|
|
|
Not this :
|
|
|
|
|
|
|
|
`function myFunc() { console.log('Hello!'); };`
|
|
|
|
|
|
|
|
You should include spaces between operators and operands, parameters, etc...
|
|
|
|
|
|
|
|
Example :
|
|
|
|
|
|
|
|
`if(dayOfWeek === 7 && weather === 'sunny') {`
|
|
|
|
|
|
|
|
`goOnTrip('beach', 'car', ['ice cream', 'bucket and spade', 'beach towel']);`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
Other rules :
|
|
|
|
|
|
|
|
```plaintext
|
|
|
|
- Don't include padding spaces after opening brackets or before closing brackets — (myVar), not ( myVar ).
|
|
|
|
|
|
|
|
- All statements must end with semicolons (";").
|
|
|
|
|
|
|
|
- Use single quotes in JavaScript, wherever single quotes are needed in syntax.
|
|
|
|
|
|
|
|
- There should be no space between a control statement keyword, function, or loop keyword and its opening parenthesis (e.g. if() { ... }, function myFunc() { ... }, for(...) { ... }).
|
|
|
|
|
|
|
|
- There should be a space between the parentheses and the opening curly brace in such cases as described in the previous bullet.
|
|
|
|
```
|
|
|
|
|
|
|
|
### Javascript comments
|
|
|
|
|
|
|
|
Use JS-style comments to comment code that isn't self-documenting:
|
|
|
|
|
|
|
|
`// This is a JavaScript-style comment`
|
|
|
|
|
|
|
|
Put your comments on separate lines preceding the code they are referring to:
|
|
|
|
|
|
|
|
`function myFunc() {`
|
|
|
|
|
|
|
|
`// Output the string 'Hello' to the browser's JS console`
|
|
|
|
|
|
|
|
`console.log('Hello');`
|
|
|
|
|
|
|
|
`// Create a new paragraph, fill it with content, and append it to the`
|
|
|
|
|
|
|
|
`let para = document.createElement('p');`
|
|
|
|
|
|
|
|
`para.textContent = 'My new paragraph';`
|
|
|
|
|
|
|
|
`document.body.appendChild(para);`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
Also note that you should leave a space between the slashes and the comment, in each case.
|
|
|
|
|
|
|
|
## Variables
|
|
|
|
|
|
|
|
### Variable naming
|
|
|
|
|
|
|
|
For variable names use lowerCamelCasing, and use concise, human-readable, semantic names where appropriate.
|
|
|
|
|
|
|
|
Do this:
|
|
|
|
|
|
|
|
`let playerScore = 0;`
|
|
|
|
|
|
|
|
`let speed = distance / time;`
|
|
|
|
|
|
|
|
not this :
|
|
|
|
|
|
|
|
`let thisIsaveryLONGVariableThatRecordsPlayerscore345654 = 0;`
|
|
|
|
|
|
|
|
`let s = d/t;`
|
|
|
|
|
|
|
|
The only place where it is OK to not use human-readable semantic names is where a very common recognized convention exists, such as using i, j, etc. for loop iterators.
|
|
|
|
|
|
|
|
### Declaring variables
|
|
|
|
|
|
|
|
When declaring variables and constants, use the let and const keywords, not var.
|
|
|
|
|
|
|
|
If a variable will not be reassigned, prefer const:
|
|
|
|
|
|
|
|
`const myName = 'Chris';`
|
|
|
|
|
|
|
|
`console.log(myName);`
|
|
|
|
|
|
|
|
Otherwise, use let:
|
|
|
|
|
|
|
|
`let myAge = '40';`
|
|
|
|
|
|
|
|
`myAge++;`
|
|
|
|
|
|
|
|
`console.log('Happy birthday!');`
|
|
|
|
|
|
|
|
##
|
|
|
|
|
|
|
|
## Operators and comparison
|
|
|
|
|
|
|
|
### Ternary operators
|
|
|
|
|
|
|
|
Ternary operators should be put on a single line:
|
|
|
|
|
|
|
|
`let status = (age >= 18) ? 'adult' : 'minor';`
|
|
|
|
|
|
|
|
Not nested:
|
|
|
|
|
|
|
|
`let status = (age >= 18)`
|
|
|
|
|
|
|
|
`? 'adult'`
|
|
|
|
|
|
|
|
`: 'minor';`
|
|
|
|
|
|
|
|
### Use strict equality
|
|
|
|
|
|
|
|
Always use strict equality and inequality.
|
|
|
|
|
|
|
|
Do this:
|
|
|
|
|
|
|
|
`name === 'Chris';`
|
|
|
|
|
|
|
|
`age !== 25;`
|
|
|
|
|
|
|
|
Not this:
|
|
|
|
|
|
|
|
`name == 'Chris';`
|
|
|
|
|
|
|
|
`age != 25;`
|
|
|
|
|
|
|
|
### Use shortcuts for boolean tests
|
|
|
|
|
|
|
|
Use shortcuts for boolean tests — use x and !x, not x === true and x === false.
|
|
|
|
|
|
|
|
## Control statements
|
|
|
|
|
|
|
|
```plaintext
|
|
|
|
- There should be no space between a control statement keyword and its opening parenthesis.
|
|
|
|
|
|
|
|
- There should be a space between the parentheses and the opening curly brace.
|
|
|
|
```
|
|
|
|
|
|
|
|
`if(iceCream) {`
|
|
|
|
|
|
|
|
`alert('Woo hoo!');`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
## Strings
|
|
|
|
|
|
|
|
### Use template literals
|
|
|
|
|
|
|
|
For inserting values into strings, use string literals.
|
|
|
|
|
|
|
|
Do this:
|
|
|
|
|
|
|
|
`let myName = 'Chris';`
|
|
|
|
|
|
|
|
`` console.log(`Hi! I'm ${myName}!`); ``
|
|
|
|
|
|
|
|
Not this :
|
|
|
|
|
|
|
|
`let myName = 'Chris';`
|
|
|
|
|
|
|
|
`console.log('Hi! I\'m' + myName + '!');`
|
|
|
|
|
|
|
|
### Use textContent, not innerHTML
|
|
|
|
|
|
|
|
When inserting strings into DOM nodes, use Node.textContent:
|
|
|
|
|
|
|
|
`let text = 'Hello to all you good people';`
|
|
|
|
|
|
|
|
`const para = document.createElement('p');`
|
|
|
|
|
|
|
|
`para.textContent = text;`
|
|
|
|
|
|
|
|
\
|
|
|
|
Not Element.innerHTML:
|
|
|
|
|
|
|
|
`let text = 'Hello to all you good people';`
|
|
|
|
|
|
|
|
`const para = document.createElement('p');`
|
|
|
|
|
|
|
|
textContent is a lot more efficient, and less error-prone than innerHTML.
|
|
|
|
|
|
|
|
## Conditionals
|
|
|
|
|
|
|
|
### General purpose looping
|
|
|
|
|
|
|
|
When loops are required, choose an appropriate loop out of the available ones (for, for...of, while, etc.). Make sure to keep the code as understandable as possible.
|
|
|
|
|
|
|
|
When using for/for...of loops, make sure to define the initializer properly, with a let keyword:
|
|
|
|
|
|
|
|
`let cats = ['Athena', 'Luna'];`
|
|
|
|
|
|
|
|
`for(let i of cats) {`
|
|
|
|
|
|
|
|
`console.log(i);`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
Not :
|
|
|
|
|
|
|
|
`let cats = ['Athena', 'Luna'];`
|
|
|
|
|
|
|
|
`for(i of cats) {`
|
|
|
|
|
|
|
|
`console.log(i);`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
### Switch statements
|
|
|
|
|
|
|
|
Format switch statements like this:
|
|
|
|
|
|
|
|
`let expr = 'Papayas';`
|
|
|
|
|
|
|
|
`switch(expr) {`
|
|
|
|
|
|
|
|
` case 'Oranges':`
|
|
|
|
|
|
|
|
` console.log('Oranges are $0.59 a pound.');`
|
|
|
|
|
|
|
|
` break;`
|
|
|
|
|
|
|
|
` case 'Papayas':`
|
|
|
|
|
|
|
|
` console.log('Mangoes and papayas are $2.79 a pound.');`
|
|
|
|
|
|
|
|
` // expected output: "Mangoes and papayas are $2.79 a pound."`
|
|
|
|
|
|
|
|
` break;`
|
|
|
|
|
|
|
|
` default:`
|
|
|
|
|
|
|
|
`` console.log(`Sorry, we are out of ${expr}`); ``
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
## Functions and objects
|
|
|
|
|
|
|
|
### Function naming
|
|
|
|
|
|
|
|
For function names use lowerCamelCasing, and use concise, human-readable, semantic names where appropriate.
|
|
|
|
|
|
|
|
Do this:
|
|
|
|
|
|
|
|
`function sayHello() {`
|
|
|
|
|
|
|
|
`alert('Hello!');`
|
|
|
|
|
|
|
|
`};`
|
|
|
|
|
|
|
|
### Defining functions
|
|
|
|
|
|
|
|
Where possible, use the function declaration to define functions over function expressions:
|
|
|
|
|
|
|
|
Do this:
|
|
|
|
|
|
|
|
`function sum(a, b) {`
|
|
|
|
|
|
|
|
`return a + b;`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
Not this :
|
|
|
|
|
|
|
|
`let sum = function(a, b) {`
|
|
|
|
|
|
|
|
`return a + b;`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
When using anonymous functions inside a method that requires a function as a parameter, it is acceptable (although not required) to use an arrow function to make the code shorter and cleaner.
|
|
|
|
|
|
|
|
`const array1 = [1, 2, 3, 4];`
|
|
|
|
|
|
|
|
`let sum = array1.reduce((a, b) =>`
|
|
|
|
|
|
|
|
`a + b`
|
|
|
|
|
|
|
|
`);`
|
|
|
|
|
|
|
|
### Creating objects
|
|
|
|
|
|
|
|
Use literals — not constructors — for creating general objects (i.e., when classes are not involved):
|
|
|
|
|
|
|
|
Do this:
|
|
|
|
|
|
|
|
`let myObject = { };`
|
|
|
|
|
|
|
|
Not this :
|
|
|
|
|
|
|
|
`let myObject = new Object();`
|
|
|
|
|
|
|
|
### Object classes
|
|
|
|
|
|
|
|
Use ES class syntax for objects, not old-style constructors.
|
|
|
|
|
|
|
|
For example:
|
|
|
|
|
|
|
|
`class Person {`
|
|
|
|
|
|
|
|
` constructor(name, age, gender) {`
|
|
|
|
|
|
|
|
` this.name = name;`
|
|
|
|
|
|
|
|
` this.age = age;`
|
|
|
|
|
|
|
|
` this.gender = gender;`
|
|
|
|
|
|
|
|
` }`
|
|
|
|
|
|
|
|
` greeting() {`
|
|
|
|
|
|
|
|
`` console.log(`Hi! I'm ${this.name}`); ``
|
|
|
|
|
|
|
|
` };`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
Use _extends_ for inheritance:
|
|
|
|
|
|
|
|
`class Teacher extends Person {`
|
|
|
|
|
|
|
|
`...`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
### Object naming
|
|
|
|
|
|
|
|
When defining an object class (as seen above), use UpperCamelCasing (also known as PascalCasing) for the class name, and lowerCamelCasing for the object property and method names.
|
|
|
|
|
|
|
|
When defining an object instance, either a literal or via a constructor, use lowerCamelCase for the instance name:
|
|
|
|
|
|
|
|
`let hanSolo = new Person('Han Solo', 25, 'male');`
|
|
|
|
|
|
|
|
`let hanSolo = {`
|
|
|
|
|
|
|
|
`name: 'Han Solo',`
|
|
|
|
|
|
|
|
`age: 25,`
|
|
|
|
|
|
|
|
`gender: 'male'`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
## Arrays
|
|
|
|
|
|
|
|
### Creating arrays
|
|
|
|
|
|
|
|
Use literals — not constructors — for creating arrays:
|
|
|
|
|
|
|
|
Do this:
|
|
|
|
|
|
|
|
`let myArray = [ ];`
|
|
|
|
|
|
|
|
Not this :
|
|
|
|
|
|
|
|
`let myArray = new Array(length);`
|
|
|
|
|
|
|
|
### Adding to an array
|
|
|
|
|
|
|
|
When adding items to an array, use push(), not direct assignment. Given the following array:
|
|
|
|
|
|
|
|
`const pets = [];`
|
|
|
|
|
|
|
|
Do this :
|
|
|
|
|
|
|
|
`pets.push('cat');`
|
|
|
|
|
|
|
|
not this :
|
|
|
|
|
|
|
|
`pets[pets.length] = 'cat';`
|
|
|
|
|
|
|
|
## Error handling
|
|
|
|
|
|
|
|
If certain states of your program throw uncaught errors, they will halt execution and potentially reduce the usefulness of the example. You should therefore catch errors using a try...catch block:
|
|
|
|
|
|
|
|
`try {`
|
|
|
|
|
|
|
|
`console.log(results);`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
`catch(e) {`
|
|
|
|
|
|
|
|
`console.error(e);`
|
|
|
|
|
|
|
|
`}`
|
|
|
|
|
|
|
|
## Documenting code
|
|
|
|
|
|
|
|
### Standard
|
|
|
|
|
|
|
|
The code will be documented according to [JSDoc conventions](https://jsdoc.app/). The full documentation is available at the webpage, the most common rules will be detailed below. The code documentation will be parsed and an independent document will be produced.
|
|
|
|
|
|
|
|
### General rules
|
|
|
|
|
|
|
|
JSDoc comments should generally be placed immediately before the code being documented. Each comment must start with a /** sequence in order to be recognized by the JSDoc parser. Comments beginning with /*, /***, or more than 3 stars will be ignored. This is a feature to allow you to suppress parsing of comment blocks.
|
|
|
|
|
|
|
|
### Documenting a function
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* Returns the sum of a and b
|
|
|
|
* @param {number} a
|
|
|
|
* @param {number} b
|
|
|
|
* @returns {number} Sum of a and b
|
|
|
|
*/
|
|
|
|
function sum(a, b) {
|
|
|
|
return a + b;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
### Documenting a class
|
|
|
|
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
* Class representing a dot.
|
|
|
|
* @extends Point
|
|
|
|
*/
|
|
|
|
class Dot extends Point {
|
|
|
|
/**
|
|
|
|
* Create a dot.
|
|
|
|
* @param {number} x - The x value.
|
|
|
|
* @param {number} y - The y value.
|
|
|
|
* @param {number} width - The width of the dot, in pixels.
|
|
|
|
*/
|
|
|
|
constructor(x, y, width) {
|
|
|
|
// ...
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the dot's width.
|
|
|
|
* @return {number} The dot's width, in pixels.
|
|
|
|
*/
|
|
|
|
getWidth() {
|
|
|
|
// ...
|
|
|
|
}
|
|
|
|
}
|
|
|
|
``` |