Skip to content

Commit e50989d

Browse files
author
Benjamin De Cock
committed
JS guidelines
0 parents  commit e50989d

File tree

1 file changed

+367
-0
lines changed

1 file changed

+367
-0
lines changed

README.md

Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
# Frontend Guidelines
2+
3+
## JavaScript
4+
5+
### Apply
6+
7+
Forget about `apply()`. Use the spread operator instead.
8+
9+
```javascript
10+
const greet = (first, last) => `Hi ${first} ${last}`;
11+
const person = ["John", "Doe"];
12+
13+
// bad
14+
greet.apply(null, person);
15+
16+
// good
17+
greet(...person);
18+
```
19+
### Arguments
20+
21+
Forget about the `arguments` object. The rest parameter is always a better option because:
22+
23+
1. it's named, so it gives you a better idea of the arguments the function is expecting
24+
2. it's a real array, which makes it easier to use.
25+
26+
```javascript
27+
// bad
28+
const sortNumbers = () =>
29+
Array.prototype.slice.call(arguments).sort();
30+
31+
// good
32+
const sortNumbers = (...numbers) => numbers.sort();
33+
```
34+
### Bind
35+
36+
Don't `bind()` when there's a more idiomatic approach.
37+
38+
```javascript
39+
// bad
40+
["foo", "bar"].forEach(func.bind(this));
41+
42+
// good
43+
["foo", "bar"].forEach(func, this);
44+
```
45+
```javascript
46+
// bad
47+
const person = {
48+
first: "John",
49+
last: "Doe",
50+
greet() {
51+
const full = function() {
52+
return `${this.first} ${this.last}`;
53+
}.bind(this);
54+
return `Hello ${full()}`;
55+
}
56+
}
57+
58+
// good
59+
const person = {
60+
first: "John",
61+
last: "Doe",
62+
greet() {
63+
const full = () => `${this.first} ${this.last}`;
64+
return `Hello ${full()}`;
65+
}
66+
}
67+
```
68+
### Caching
69+
70+
Cache feature tests, large data structures and any expensive operation.
71+
72+
```javascript
73+
// bad
74+
const contains = (arr, value) =>
75+
Array.prototype.includes
76+
? arr.includes(value)
77+
: arr.some(el => el === value);
78+
contains(["foo", "bar"], "baz"); // => false
79+
80+
// good
81+
const contains = (() =>
82+
Array.prototype.includes
83+
? (arr, value) => arr.includes(value)
84+
: (arr, value) => arr.some(el => el === value)
85+
)();
86+
contains(["foo", "bar"], "baz"); // => false
87+
```
88+
### Higher-order functions
89+
90+
Avoid nesting functions when you don't have to.
91+
92+
```javascript
93+
// bad
94+
[1, 2, 3].map(num => String(num));
95+
96+
// good
97+
[1, 2, 3].map(String);
98+
```
99+
### Coercion
100+
101+
Embrace implicit coercion when it makes sense. Avoid it otherwise. Don't cargo-cult.
102+
103+
```javascript
104+
// bad
105+
if (x === undefined || x === null) { ... }
106+
107+
// good
108+
if (x == undefined) { ... }
109+
```
110+
### Composition
111+
112+
Avoid multiple nested function calls. Use composition instead.
113+
114+
```javascript
115+
// bad
116+
const plus1 = a => a + 1;
117+
const mult2 = a => a * 2;
118+
119+
mult2(plus1(5)); // => 12
120+
121+
122+
// good
123+
const pipeline = (...funcs) =>
124+
val => funcs.reduce((a, b) => b(a), val);
125+
126+
const plus1 = a => a + 1;
127+
const mult2 = a => a * 2;
128+
const addThenMult = pipeline(plus1, mult2);
129+
130+
addThenMult(5); // => 12
131+
```
132+
### Conditions
133+
134+
Favor IIFE's and return statements over if, else if, else and switch statements.
135+
136+
```javascript
137+
// bad
138+
var grade;
139+
if (result < 50)
140+
grade = "bad";
141+
else if (result < 90)
142+
grade = "good";
143+
else
144+
grade = "excellent";
145+
146+
// good
147+
const grade = (() => {
148+
if (result < 50)
149+
return "bad";
150+
if (result < 90)
151+
return "good";
152+
return "excellent";
153+
})();
154+
```
155+
### Curry
156+
157+
Currying might have its place in other languages, but avoid it in JavaScript. It makes your code harder to read by introducing a foreign paradigm while the appropriate use cases are extremely unusual.
158+
159+
```javascript
160+
// bad
161+
const sum = a => b => a + b;
162+
sum(5)(3); // => 8
163+
164+
// good
165+
const sum = (a, b) => a + b;
166+
sum(5, 3); // => 8
167+
```
168+
### Dependencies
169+
170+
Minimize dependencies. Third-party is code you don't know. Don't load an entire library for just a couple of methods easily replicable:
171+
172+
```javascript
173+
// bad
174+
var _ = require("underscore");
175+
_.compact(["foo", 0]));
176+
_.unique(["foo", "foo"]);
177+
_.union(["foo"], ["bar"], ["foo"]);
178+
179+
// good
180+
const compact = arr => arr.filter(el => el);
181+
const unique = arr => [...Set(arr)];
182+
const union = (...arr) => unique([].concat(...arr));
183+
184+
compact(["foo", 0]);
185+
unique(["foo", "foo"]);
186+
union(["foo"], ["bar"], ["foo"]);
187+
```
188+
### Loops
189+
190+
Don't use loops as they force you to use mutable objects. Rely on `array.prototype` methods.
191+
192+
```javascript
193+
// bad
194+
const sum = arr => {
195+
var sum = 0;
196+
var i = -1;
197+
for (;arr[++i];) {
198+
sum += arr[i];
199+
}
200+
return sum;
201+
};
202+
203+
sum([1, 2, 3]); // => 6
204+
205+
// good
206+
const sum = arr =>
207+
arr.reduce((x, y) => x + y);
208+
209+
sum([1, 2, 3]); // => 6
210+
```
211+
If you can't, or if using `array.prototype` methods is arguably abusive, use recursion.
212+
```javascript
213+
// bad
214+
const createDiv = howMany => {
215+
while (howMany--) {
216+
document.body.insertAdjacentHTML("beforeend", "<div></div>");
217+
}
218+
};
219+
createDiv(5);
220+
221+
// bad
222+
const createDivs = howMany =>
223+
[...Array(howMany)].forEach(() =>
224+
document.body.insertAdjacentHTML("beforeend", "<div></div>")
225+
);
226+
createDiv(5);
227+
228+
// good
229+
const createDiv = howMany => {
230+
if (!howMany) return;
231+
document.body.insertAdjacentHTML("beforeend", "<div></div>");
232+
return createDiv(howMany - 1);
233+
};
234+
createDiv(5);
235+
```
236+
### Natives
237+
238+
Rely on native methods as much as possible.
239+
240+
```javascript
241+
// bad
242+
const toArray = obj => [].slice.call(obj);
243+
244+
// good
245+
const toArray = (() =>
246+
Array.from ? Array.from : obj => [].slice.call(obj)
247+
)();
248+
```
249+
### Object iteration
250+
251+
Avoid `for...in` when you can.
252+
253+
```javascript
254+
const shared = { foo: "foo" };
255+
const obj = Object.create(shared, {
256+
bar: {
257+
value: "bar",
258+
enumerable: true
259+
}
260+
});
261+
262+
// bad
263+
for (var prop in obj) {
264+
if (obj.hasOwnProperty(prop))
265+
console.log(prop);
266+
}
267+
268+
// good
269+
Object.keys(obj).forEach(prop => console.log(prop));
270+
```
271+
### Performance
272+
273+
Favor readability, correctness and expressiveness over performance. JavaScript will basically never be your performance bottleneck. Optimize things like image compression, network access and DOM reflows instead.
274+
275+
```javascript
276+
// bad (albeit way faster)
277+
const arr = [1, 2, 3, 4];
278+
const len = arr.length;
279+
var i = -1;
280+
var result = [];
281+
while (++i < len) {
282+
var n = arr[i];
283+
if (n % 2 > 0) continue;
284+
result.push(n * n);
285+
}
286+
287+
// good
288+
const arr = [1, 2, 3, 4];
289+
const isEven = n => n % 2 == 0;
290+
const square = n => n * n;
291+
292+
const result = arr.filter(isEven).map(square);
293+
```
294+
### Readability
295+
296+
Don't obfuscate the intent of your code by using seemingly smart tricks.
297+
298+
```javascript
299+
// bad
300+
foo || doSomething();
301+
302+
// good
303+
if (!foo) doSomething();
304+
```
305+
```javascript
306+
// bad
307+
void function() { /* IIFE */ }();
308+
309+
// good
310+
(function() { /* IIFE */ }());
311+
```
312+
```javascript
313+
// bad
314+
const n = ~~3.14;
315+
316+
// good
317+
const n = Math.floor(3.14);
318+
```
319+
### Code reuse
320+
321+
Don't be afraid of creating lots of small, highly composable and reusable functions.
322+
323+
```javascript
324+
// bad
325+
arr[arr.length - 1];
326+
327+
// good
328+
const first = arr => arr[0];
329+
const last = arr => first(arr.slice(-1));
330+
last(arr);
331+
```
332+
```javascript
333+
// bad
334+
const product = (a, b) => a * b;
335+
const triple = n => n * 3;
336+
337+
// good
338+
const product = (a, b) => a * b;
339+
const triple = product.bind(null, 3);
340+
```
341+
### Statelessness
342+
343+
Try to keep your functions pure. All functions should ideally produce no side-effects, use no outside data and return new objects instead of mutating existing ones.
344+
345+
```javascript
346+
// bad
347+
const merge = (target, ...sources) => Object.assign(target, ...sources);
348+
merge({ foo: "foo" }, { bar: "bar" }); // => { foo: "foo", bar: "bar" }
349+
350+
// good
351+
const merge = (...sources) => Object.assign({}, ...sources);
352+
merge({ foo: "foo" }, { bar: "bar" }); // => { foo: "foo", bar: "bar" }
353+
```
354+
### Variables
355+
356+
Favor `const` over `let` and `let` over `var`.
357+
358+
```javascript
359+
// bad
360+
var obj = {};
361+
obj["foo" + "bar"] = "baz";
362+
363+
// good
364+
const obj = {
365+
["foo" + "bar"]: "baz"
366+
};
367+
```

0 commit comments

Comments
 (0)