Update Javascript coding guidelines authored by Moreau Nicolas's avatar Moreau Nicolas
\[\[_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() {
// ...
}
}
```