javascript.md 4.3 KB
Newer Older
C
Clement Ho 已提交
1 2
# JavaScript style guide

3 4
We use [Airbnb's JavaScript Style Guide](https://github.com/airbnb/javascript) and it's accompanying
linter to manage most of our JavaScript style guidelines.
C
Clement Ho 已提交
5

6 7
In addition to the style guidelines set by Airbnb, we also have a few specific rules
listed below.
C
Clement Ho 已提交
8 9 10 11

> **Tip:**
You can run eslint locally by running `yarn eslint`

12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
## Avoid forEach

Avoid forEach when mutating data. Use `map`, `reduce` or `filter` instead of `forEach`
when mutating data. This will minimize mutations in functions,
which aligns with [Airbnb's style guide](https://github.com/airbnb/javascript#testing--for-real).

```javascript
// bad
users.forEach((user, index) => {
  user.id = index;
});

// good
const usersWithId = users.map((user, index) => {
  return Object.assign({}, user, { id: index });
});
```

## Limit number of parameters

If your function or method has more than 3 parameters, use an object as a parameter
instead.

```javascript
// bad
function a(p1, p2, p3) {
  // ...
};

// good
function a(p) {
  // ...
};
```

## Avoid side effects in constructors

Avoid making asynchronous calls, API requests or DOM manipulations in the `constructor`.
Move them into separate functions instead. This will make tests easier to write and
code easier to maintain.
C
Clement Ho 已提交
52

53 54 55 56 57 58 59 60
```javascript
// bad
class myClass {
  constructor(config) {
    this.config = config;
    axios.get(this.config.endpoint)
  }
}
61

62 63 64 65 66
// good
class myClass {
  constructor(config) {
    this.config = config;
  }
C
Clement Ho 已提交
67

68 69 70 71 72 73 74
  makeRequest() {
    axios.get(this.config.endpoint)
  }
}
const instance = new myClass();
instance.makeRequest();
```
C
Clement Ho 已提交
75

76
## Avoid classes to handle DOM events
C
Clement Ho 已提交
77

78 79
If the only purpose of the class is to bind a DOM event and handle the callback, prefer
using a function.
80

81 82 83 84 85 86
```javascript
// bad
class myClass {
  constructor(config) {
    this.config = config;
  }
C
Clement Ho 已提交
87

88 89 90 91
  init() {
    document.addEventListener('click', () => {});
  }
}
92

93
// good
C
Clement Ho 已提交
94

95 96 97 98 99 100
const myFunction = () => {
  document.addEventListener('click', () => {
    // handle callback here
  });
}
```
C
Clement Ho 已提交
101

102
## Pass element container to constructor
103

104 105
When your class manipulates the DOM, receive the element container as a parameter.
This is more maintainable and performant.
C
Clement Ho 已提交
106

107 108 109 110 111 112 113
```javascript
// bad
class a {
  constructor() {
    document.querySelector('.b');
  }
}
114

115 116 117 118 119 120 121
// good
class a {
  constructor(options) {
    options.container.querySelector('.b');
  }
}
```
122

123
## Use ParseInt
124

125
Use `ParseInt` when converting a numeric string into a number.
C
Clement Ho 已提交
126

127 128 129
```javascript
// bad
Number('10')
130

131 132 133
// good
parseInt('10', 10);
```
C
Clement Ho 已提交
134

135
## CSS Selectors - Use `js-` prefix
136

137 138
If a CSS class is only being used in JavaScript as a reference to the element, prefix
the class name with `js-`.
139

140 141 142
```html
// bad
<button class="add-user"></button>
143

144 145 146
// good
<button class="js-add-user"></button>
```
C
Clement Ho 已提交
147

148
## Absolute vs relative paths for modules
149

150
Use relative paths if the module you are importing is less than two levels up.
C
Clement Ho 已提交
151

152 153 154
```javascript
// bad
import GitLabStyleGuide from '~/guides/GitLabStyleGuide';
155

156 157 158
// good
import GitLabStyleGuide from '../GitLabStyleGuide';
```
C
Clement Ho 已提交
159

160
If the module you are importing is two or more levels up, use an absolute path instead:
C
Clement Ho 已提交
161

162 163 164
```javascript
// bad
import GitLabStyleGuide from '../../../guides/GitLabStyleGuide';
165

166 167 168
// good
import GitLabStyleGuide from '~/GitLabStyleGuide';
```
C
Clement Ho 已提交
169

170
Additionally, **do not add to global namespace**.
171

172
## Do not use `DOMContentLoaded` in non-page modules
C
Clement Ho 已提交
173

174 175 176
Imported modules should act the same each time they are loaded. `DOMContentLoaded`
events are only allowed on modules loaded in the `/pages/*` directory because those
are loaded dynamically with webpack.
C
Clement Ho 已提交
177

178
## Avoid XSS
179

180 181
Do not use `innerHTML`, `append()` or `html()` to set content. It opens up too many
vulnerabilities.
C
Clement Ho 已提交
182

183
## Disabling ESLint in new files
184

185 186
Do not disable ESLint when creating new files. Existing files may have existing rules
disabled due to legacy compatibility reasons but they are in the process of being refactored.
C
Clement Ho 已提交
187

188 189
Do not disable specific ESLint rules. Due to technical debt, you may disable the following
rules only if you are invoking/instantiating existing code modules.
C
Clement Ho 已提交
190

M
Marcel Amirault 已提交
191 192
- [no-new](http://eslint.org/docs/rules/no-new)
- [class-method-use-this](http://eslint.org/docs/rules/class-methods-use-this)
193

194 195
> Note: Disable these rules on a per line basis. This makes it easier to refactor
  in the future. E.g. use `eslint-disable-next-line` or `eslint-disable-line`.