-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathjs_style_guide.html
535 lines (380 loc) · 16.5 KB
/
js_style_guide.html
1
2
3
4
5
6
7
8
9
10
11
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
<!DOCTYPE html>
<html>
<head>
<title>Javascript Style Guide - Unboxed Consulting</title>
<style type="text/css">
html {
background-color: #ccc;
}
body {
font-family: helvetica, arial;
color: #555;
max-width: 700px;
line-height: 1.4em;
font-size: 90%;
margin-left: auto;
margin-right: auto;
background-color: white;
padding: 20px;
}
h2 { margin-top: 50px; }
h3 { margin-top: 50px; border-bottom: solid 1px #999; text-indent: 3px; }
h4 { margin-top: 30px; }
.code {
background-color: #eee;
color: #333;
font-family: monospace;
color: #0000cc;
display: inline-block;
padding: 0 5px;
}
code {
padding: 0 7px;
}
.good {
background-color: #d8f6dd;
}
.bad {
background-color: #fdd;
}
</style>
</head>
<body>
<h1>Javascript style guide - Unboxed Consulting</h1>
<p>First Draft</p>
<h2>Preamble</h2>
<p>
This is intended as a set of guidelines only. It is not intended to be a book of absolute rules
and consistency with any existing code base should always be held as more important that this document.
</p>
<p>
It is also intended to be a living document and should be continuously updated where experience shows
it to be incorrect.
</p>
<h2>TLDR;</h2>
<ul>
<li>FullCamel case for namespaces and constructors.</li>
<lI>lowercase_underscored for variables and functions.</lI>
<li>UPPERCASE_UNDERSCORED for constants.</li>
<li>Name verbosely, try to make function names explain what the function does.</li>
<li>2 Spaces for indentation.</li>
<li>Use the constructor pattern.</li>
<li>Use named parameters where parameter meaning is not implicit in function calls.</li>
<li>Use '<span class="code">self</span>' for holding construction object in closure.</li>
<li>Use exceptions. Never code to fail silently.</li>
</ul>
<h2>House Style</h2>
<h3>Naming conventions</h3>
<h4>Cases</h4>
<table>
<tbody>
<tr>
<td>Namespaces</td>
<td>FullCamel</td>
<td>UbxdWeb</td>
</tr>
<tr>
<td>Constructors</td>
<td>FullCamel</td>
<td>UbxdWeb.Carousel</td>
</tr>
<tr>
<td>Variables</td>
<td>lowercase_underscored</td>
<td>price_of_cheese</td>
</tr>
<tr>
<td>Functions</td>
<td>lowercase_underscored</td>
<td>get_price_of_cheese()</td>
</tr>
<tr>
<td>Constants</td>
<td>UPPERCASE_UNDERSCORED</td>
<td>KG_PER_POUND</td>
</tr>
</tbody>
</table>
<p>
Given we are predominately a ruby house, these have been chosen to reflect the ruby conventions.
</p>
<h4>Functions</h4>
<p>Avoid using anonymous functions. Note that a function assigned to an object attribute is anonymous unless explicitly given a name:</p>
<p>bad:</p>
<pre class="bad"><code>this.do_the_macarana = function () {
//...
}</code></pre>
<p>Although assigned to a meaningful attribute, this function itself is anonymous.</p>
<p>good:</p>
<pre class="good"><code>this.do_the_macarana = function do_the_macarana() {
//...
}</code></pre>
<p>
An application made up of entirely anonymous functions is almost impossible to effectively profile, and stack traces end up being pretty meaningless.
</p>
<p>
Some small functions passed as arguments (maybe as callbacks or event handlers) may not really have a suitable name, in which case leaving them anonymous is appropriate.
</p>
<h4>More about naming</h4>
<p>Function naming is extremely important. Descriptive function names can really make the difference between readable and unreadable code. Be verbose. Having really long function or variable names is not a problem; Javascript can be minified.</p>
<h4>Commenting</h4>
<p>Feel free to comment anything obscure, but there is no need to comment the obvious.</p>
<p>If you find yourself needing to comment a lot, consider breaking the code up into named functions which serve to describe what the code is doing.</p>
<p>If working on a previously commented piece of code, be sure to change the comments to ensure they are still accurate.</p>
<h3>Code Formatting</h3>
<h4>Curly Braces</h4>
<p>Because of implicit semicolon insertion, always start your curly braces on the same line as whatever they're opening. For example:</p>
<pre class="good"><code>if (something) {
// ...
}
else {
// ...
}</code></pre>
<h4>Array and Object Initializers</h4>
<p>Single-line array and object initializers are allowed when they fit on a line:</p>
<pre class="good"><code>var arr = [1, 2, 3]; // No space after [ or before ].
var obj = {a: 1, b: 2, c: 3}; // No space after { or before }.</code></pre>
<p>Multiline array initializers and object initializers are indented 2 spaces, just like blocks.</p>
<pre class="good"><code>var inset = {
top: 10,
right: 20,
bottom: 15,
left: 12
};</code></pre>
<p>Note that values are aligned with no space between the key and the colon.</p>
<pre class="good"><code>this.rows = [
'"Slartibartfast" <fjordmaster@magrathea.com>',
'"Zaphod Beeblebrox" <theprez@universe.gov>',
'"Ford Prefect" <ford@theguide.com>',
'"Arthur Dent" <has.no.tea@gmail.com>',
'"Marvin the Paranoid Android" <marv@googlemail.com>',
'the.mice@magrathea.com'
];</code></pre>
<h4>Function Calls</h4>
<p>Simple function calls should all be on one line:</p>
<code class="good">activate(the_laser, '100000V');</code>
<p>Function calls with extremely long arguments or lots of them should be split into 1 line per argument, starting on the second line:</p>
<pre class="good"><code>activate(
the_super_multi_laser_array,
'100000000000000000000000000000000000000000V'
);</code></pre>
<p>Additionally, if the arguments contain an object (hashlike), it should always be written multiline:</p>
<pre class="good"><code>activate(
the_super_multi_laser_array,
settings: {
voltage: 100000000000000000000000000,
target: "John Prescott's bald spot"
}
);</code></pre>
<h4>Indentation</h4>
<p>Use 2 spaces for indentation.</p>
<h3>Constructors</h3>
<p>There are several different ways of constructing objects. In general the constructor pattern is recommended:</p>
<pre class="good"><code>function Laser() {
this.fire = function fire() {
//...
}
}
window.the_laser = new Laser();</code></pre>
<p>Nested constructors are also fine but try to keep stuff separate where possible.</p>
<pre class="good"><code>function Laser() {
var power_supply = new PowerSupply();
this.fire = function fire() {
power_supply.turn_on();
//...
}
function PowerSupply() {
//...
}
}</code></pre>
<h3>Modular Behaviour</h3>
<p>Common behaviour can be bundled into modules:</p>
<pre class="good"><code>function PoweredThing() {
this.set_voltage = function set_voltage() {
//...
}
}
function Laser() {
PoweredThing.apply(this);
}
var laser = new Laser();
laser.set_voltage(100000000);</code></pre>
<h3>Self</h3>
<p>Often, it's required to hold the constructed object in closure for use by private functions. Use the variable name self for this:</p>
<pre class="good"><code>function Laser() {
var self = this;
function fire() {
set_voltage(self.voltage);
}
}</code></pre>
<p>Note that this should always be the first line of the constructor.</p>
<h3>Using named parameters</h3>
<p>Using named parameters reduces connescence and makes code more readable. It is encouraged when a function's parameters are not immediately obvious from the function name.</p>
<p>Bad:</p>
<pre class="bad"><code>function do_the_macarana(tempo, start_at_step, repeats) {
//...
}
do_the_macarana(120, 5, 3);</code></pre>
<p>Here, it's not obvious reading the function call what the parameters are doing and anyone looking at the code would have to look up the function definition to understand the code.</p>
<p>Good:</p>
<pre class="good"><code>function do_the_macarana(params) {
//params: tempo, start_at_step, repeats
}
do_the_macarana({
tempo: 120,
start_at_step: 5,
repeats: 3
});</code></pre>
<p>or</p>
<pre class="good"><code>function do_the_macarana(params) {
var tempo = params.tempo;
var start_at_step = params.start_at_step;
var repeats = params.repeats;
}
do_the_macarana({
tempo: 120,
start_at_step: 5,
repeats: 3
});</code></pre>
<p>Here, it's immediately apparent what the purpose of each parameter is when reading the function call.</p>
<p>Which parameters are consumed should be immediately visible at the start of the function definition. When defining a function, either var all the members of params which you are interested in using, or leave a comment saying which params are being used.</p>
<h2>Code Layout</h2>
<h3>Files</h3>
<p>In general, one file should be created for each constructor. All files should be named in lower_underscored case and should reflect the constructor.</p>
<p>Vendor stuff (jQuery, CKEditor, etc.) should be in the /vendor folder</p>
<p>Lib stuff (Utilities, any other non-vendor libraries which are not specific to a single part of the application) should be in the /lib folder.</p>
<p>application.js should only include code to initialize the application.</p>
<h3>Code in views</h3>
<p>It is acceptable to have inline javascript code, but only initializers related to the page content. In general, wherever possible, javascript code should be kept out of the view.</p>
<p>It's acceptable to set any required application constants inline.</p>
<p>Of course, drop-in code like google analytics is also acceptable.</p>
<p>Use of javascript in html attributes is bad:</p>
<code class="bad"><a onclick="do_something();">Do Something</a></code>
<p>Make use of <a href="http://en.wikipedia.org/wiki/Unobtrusive_JavaScript" title="Unobtrusive JavaScript on Wikipedia">unobtrusive javascript</a> in order to separate the functionality (the "behaviour layer") from a Web page's structure/content and presentation.</p>
<h2>Language rules</h2>
<h3>Var</h3>
<p>Always use <span class="code">var</span>. Never use implicit assignment.</p>
<p>If you wish something to be declared on window, be explicit:</p>
<p>wrong:</p>
<code class="bad">foo = 'bar';</code>
<p>right:</p>
<code class="good">window.foo = 'bar';</code>
<h3>Constants</h3>
<p>Constants should be defined as normal variables but should obey the naming conventions for constants. The <span class="code">const</span> keyword is not well supported and thus should not be used.</p>
<h3>Semicolons</h3>
<p>Never rely on inferred insertion of semicolons. Semicolons are required after all assignments or function calls. Semicolons are not required after blocks.</p>
<p>It's also recommended to use semicolon after function declarations even though they are not required.</p>
<p>Semicolons should not be used after <span class="code">for</span> / <span class="code">while</span> / <span class="code">switch</span> / <span class="code">if</span> / <span class="code">else</span> blocks and other similar constructions for readability.</p>
<pre><code>var foo = 'bar';
// assignment - needs a semicolon.
function foo() {
alert("don't you foo me");
//function call, needs a semicolon.
};
// Doesn't need a semicolon, but should have one.
this.foo = function foo() {
alert("don't you foo me");
};
// This must have a semicolon as it is an assignment.
if (foo) {
foo();
}
// Should not have a semicolon.</code></pre>
<h3>Nested Functions</h3>
<p>Nested functions are a great way to break up a function and can be used liberally. If a function is used exclusively by another function, it should in general be declared within that function.</p>
<p>Bad:</p>
<pre class="bad"><code>function foo_plus_bar() {
return get_foo_for_foo_plus_bar() + 'bar';
};
function get_foo_for_foo_plus_bar() {
return 'foo';
};</code></pre>
<p>Good:</p>
<pre class="good"><code>function foo_plus_bar() {
function get_foo() {
return 'foo';
};
return get_foo() + 'bar';
};</code></pre>
<p>As an exception to this, sometimes you may have to declare a 'child' function outside of the main function to avoid a circular reference (see section on closures).</p>
<h3>Declarations within blocks</h3>
<p>In general, avoid making any declarations within blocks. Especially, absolutely do not define functions within blocks as this is not part of ECMAScript. ECMAScript only allows for Function Declarations in the root statement list of a script or function.</p>
<p class="Bad:">Terrible:</p>
<pre class="bad"><code>if (foo_is_wibble) {
function foo() { return 'wibble'; }
}
else {
function foo() { return 'bar'; }
}
foo();</code></pre>
<p>Ok:</p>
<pre class="good"><code>function wibble() {
return 'wibble';
}
function bar() {
return 'bar';
}
var foo;
if (foo_is_wibble) {
foo = wibble;
}
else {
foo = bar;
}
foo();</code></pre>
<p>In general, variables should also not be declared in blocks:</p>
<p>bad:</p>
<pre class="bad"><code>for (var i=0; i<5 i++) {
var wibble = new Wibble(i);
wibbles.push(bar);
}</code></pre>
<p>good:</p>
<pre class="good"><code>var wibble;
for (var i=0; i<5 i++) {
wibble = new Wibble(i);
wibbles.push(wibble);
}</code></pre>
<h3>Exceptions</h3>
<p>Use exceptions. Throw stuff whenever you need to. The only thing to avoid is using try / catch blocks for 'happy path' execution. Try / catch blocks are expensive and should only be used for exception handling.</p>
<p>Don't be afraid of throwing custom exceptions. If something is broken, it's broken and a good error message will save time in debugger. Never code to fail silently.</p>
<h3>Creating primitive objects</h3>
<p>Do not use wrapper objects. Just declare the primitive directly:</p>
<pre class="good"><code>var str = 'foo';
var bool = false;
var arr = [];
var num = 10;
var obj = {};</code></pre>
<p>Especially, never use the <span class="code">new</span> keyword with primitive constructors. Here's why:</p>
<pre><code>typeof(Boolean()) //==> 'boolean'
typeof(new Boolean()) //==> 'object'</code></pre>
<p>There are only five primitive types in javascript, these are</p>
<p class="code">undefined, null, boolean, number, and string</p>
<h3>Closures</h3>
<p>Closures are great. Closures can inspire genuine awe. However, consideration must sometimes be taken in their use, especially in long-running code.</p>
<p>Consider this:</p>
<pre><code>function foo(element, a, b) {
element.onclick = function handle_click() { /* uses a and b */ };
}</code></pre>
<p>Here, we have created a circular reference which will cause a memory leak. The function <span class="code">handle_click</span> holds <span class="code">element</span> in scope, and <span class="code">element</span> holds <span class="code">handle_click</span>, meaning that neither can be destroyed.</p>
<pre class="good"><code>function foo(element, a, b) {
element.onclick = bar(a, b);
}
function bar(a, b) {
return function() { /* uses a and b */ }
}</code></pre>
<p>Here a second closure not containing <span class="code">element</span> is created, thus avoiding the circular reference.</p>
<h3>Eval</h3>
<p>In general, the only use for <span class="code">eval</span> is to deserialize stuff. If you find yourself trying to use it for anything else, you're probably being too 'meta'.</p>
<h3>With</h3>
<p>In general, just don't. Use of the with keyword can easily mask scope and produce extremely confusing code to read.</p>
<h3>This</h3>
<p>Use of '<span class="code">this</span>' can be confusing. In general it should be limited to being used within constructors and in conjunction with <span class="code">call</span> or <span class="code">apply</span>.</p>
<p>Using <span class="code">this</span> to target DOM elements in event calls generally hints at a bad code structure, and consideration should be given to how to achieve the same results in a different way.</p>
<h3>For … in … loops</h3>
<p>This method should not be used to iterate over an array.</p>
<h3>Modifying prototypes of built-in objects</h3>
<p>for example:</p>
<code class="bad">Array.prototype.find = function () {....}</code>
<p>Native wrapped constructors should never be modified. If you need to extend the functionality of a native type, create a new constructor which creates an object and then attaches any extended stuff to it.</p>
</body>
</html>