· 9 years ago · Nov 25, 2016, 07:58 PM
1# ClockCrew JavaScript Style Guide() {
2
3*It's time to code*
4
5## Table of Contents
6
7 1. [Types](#types)
8 1. [Objects](#objects)
9 1. [Arrays](#arrays)
10 1. [Strings](#strings)
11 1. [Functions](#functions)
12 1. [Properties](#properties)
13 1. [Variables](#variables)
14 1. [Hoisting](#hoisting)
15 1. [Conditional Expressions & Equality](#conditional-expressions--equality)
16 1. [Blocks](#blocks)
17 1. [Comments](#comments)
18 1. [Whitespace](#whitespace)
19 1. [Commas](#commas)
20 1. [Semicolons](#semicolons)
21 1. [Type Casting & Coercion](#type-casting--coercion)
22 1. [Naming Conventions](#naming-conventions)
23 1. [Accessors](#accessors)
24 1. [Constructors](#constructors)
25 1. [Events](#events)
26 1. [Promises](#promises)
27 1. [Modules](#modules)
28 1. [jQuery](#jquery)
29 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility)
30 1. [Testing](#testing)
31 1. [Performance](#performance)
32 1. [Resources](#resources)
33 1. [License](#license)
34
35## Types
36
37 - [1.1](#1.1) <a name='1.1'></a> **Primitives**: When you access a primitive type you work directly on its value.
38
39 + `string`
40 + `number`
41 + `boolean`
42 + `null`
43 + `undefined`
44
45 ```javascript
46 const count = 1;
47 let number = count;
48
49 number = 9;
50
51 console.log(count, number); // => 1, 9
52 ```
53 - [1.2](#1.2) <a name='1.2'></a> **Complex**: When you access a complex type you work on a reference to its value.
54
55 + `object`
56 + `array`
57 + `function`
58
59 ```javascript
60 const integers = [1, 2];
61 const numbers = integer;
62
63 numbers[0] = 9;
64
65 console.log(intergers[0], numbers[0]); // => 9, 9
66 ```
67
68**[⬆ back to top](#table-of-contents)**
69
70## References
71
72 Constants at the top!
73
74 - [2.1](#2.1) <a name='2.1'></a> Use `const` for all of your references; avoid using `var`.
75
76 > Why? This ensures that you can't reassign your references during the lifecycle of the application, which can lead to bugs and difficult to comprehend code.
77
78 eslint rules: [`prefer-const`](http://eslint.org/docs/rules/prefer-const.html), [`no-const-assign`](http://eslint.org/docs/rules/no-const-assign.html).
79
80 ```javascript
81 // bad
82 var count = 1;
83 var fruit = 'banana';
84
85 // good
86 const count = 1;
87 const fruit = 'banana';
88 ```
89
90 - [2.2](#2.2) <a name='2.2'></a> If you must reassign references, use `let` instead of `var`.
91
92 > Why? `let` is block-scoped rather than function-scoped like `var`.
93
94 eslint rules: [`no-var`](http://eslint.org/docs/rules/no-var.html).
95
96 ```javascript
97 // bad
98 var count = 1;
99 if (true) {
100 count += 1;
101 }
102
103 // good, use the let.
104 let count = 1;
105 if (true) {
106 count += 1;
107 }
108 ```
109
110 - [2.3](#2.3) <a name='2.3'></a> Note that both `let` and `const` are block-scoped.
111
112 ```javascript
113 // const and let only exist in the blocks they are defined in.
114 {
115 let count = 1;
116 const number = 1;
117 }
118 console.log(count); // ReferenceError
119 console.log(number); // ReferenceError
120 ```
121
122**[⬆ back to top](#table-of-contents)**
123
124## Objects
125
126 - Use the literal syntax for object creation.
127
128 ```javascript
129 // bad
130 const item = new Object();
131
132 // good
133 const item = {};
134 ```
135
136 - Don't use [reserved words](http://es5.github.io/#x7.6.1) as keys. It won't work in IE8. [More info](https://github.com/airbnb/javascript/issues/61)
137
138 ```javascript
139 // bad
140 const optimusPrime = {
141 default: { mode: 'car' },
142 private: true
143 };
144
145 // good
146 const optimusPrime = {
147 defaults: { mode: 'car' },
148 hidden: true
149 };
150 ```
151
152 - Use readable synonyms in place of reserved words.
153
154 ```javascript
155 // bad
156 const optimusPrime = {
157 class: 'alien'
158 };
159
160 // bad
161 const optimusPrime = {
162 klass: 'alien'
163 };
164
165 // good
166 const optimusPrime = {
167 type: 'alien'
168 };
169 ```
170
171**[⬆ back to top](#table-of-contents)**
172
173
174## Arrays
175
176 - Use the literal syntax for array creation
177
178 ```javascript
179 // bad
180 const items = new Array();
181
182 // good
183 const items = [];
184 ```
185
186 - If you don't know array length use Array#push.
187
188 ```javascript
189 const someStack = [];
190
191
192 // bad
193 someStack[someStack.length] = 'abracadabra';
194
195 // good
196 someStack.push('abracadabra');
197 ```
198
199 - When you need to copy an array use Array#slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7)
200
201 ```javascript
202 const len = items.length;
203 const itemsCopy = [];
204 let i;
205
206 // bad
207 for (i = 0; i < len; i++) {
208 itemsCopy[i] = items[i];
209 }
210
211 // good
212 itemsCopy = items.slice();
213 ```
214
215 - To convert an array-like object to an array, use Array#slice.
216
217 ```javascript
218 function trigger() {
219 const args = Array.prototype.slice.call(arguments);
220 ...
221 }
222 ```
223
224**[⬆ back to top](#table-of-contents)**
225
226
227## Strings
228
229 - Use single quotes `''` for strings
230
231 ```javascript
232 // bad
233 const name = "Steven Hawkings";
234
235 // good
236 const name = 'Steven Hawkings';
237
238 // bad
239 const fullName = "Steven " + this.lastName;
240
241 // good
242 const fullName = 'Steven ' + this.lastName;
243 ```
244
245 - Strings longer than 120 characters should be written across multiple lines using string concatenation.
246 - Note: If overused, long strings with concatenation could impact performance. [jsPerf](http://jsperf.com/ya-string-concat) & [Discussion](https://github.com/airbnb/javascript/issues/40)
247
248 ```javascript
249 // bad
250 const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
251
252 // bad
253 const errorMessage = 'This is a super long error that was thrown because \
254 of Batman. When you stop to think about how Batman had anything to do \
255 with this, you would get nowhere \
256 fast.';
257
258 // good
259 const errorMessage = 'This is a super long error that was thrown because ' +
260 'of Batman. When you stop to think about how Batman had anything to do ' +
261 'with this, you would get nowhere fast.';
262 ```
263
264 - When programmatically building up a string, use Array#join instead of string concatenation. Mostly for IE: [jsPerf](http://jsperf.com/string-vs-array-concat/2).
265
266 ```javascript
267 const items;
268 const messages;
269 const length;
270 const i;
271
272 messages = [{
273 state: 'success',
274 message: 'This one worked.'
275 }, {
276 state: 'success',
277 message: 'This one worked as well.'
278 }, {
279 state: 'error',
280 message: 'This one did not work.'
281 }];
282
283 length = messages.length;
284
285 // bad
286 function inbox(messages) {
287 items = '<ul>';
288
289 for (i = 0; i < length; i++) {
290 items += '<li>' + messages[i].message + '</li>';
291 }
292
293 return items + '</ul>';
294 }
295
296 // good
297 function inbox(messages) {
298 items = [];
299
300 for (i = 0; i < length; i++) {
301 items[i] = messages[i].message;
302 }
303
304 return '<ul><li>' + items.join('</li><li>') + '</li></ul>';
305 }
306 ```
307
308**[⬆ back to top](#table-of-contents)**
309
310
311## Functions
312
313 - Function expressions:
314
315 ```javascript
316 // anonymous function expression
317 const anonymous = function() {
318 return true;
319 };
320
321 // named function expression
322 const named = function named() {
323 return true;
324 };
325
326 // immediately-invoked function expression (IIFE)
327 (function() {
328 console.log('Welcome to the Internet. Please follow me.');
329 })();
330 ```
331
332 - Never declare a function in a non-function block (if, while, etc). Assign the function to a variable instead. Browsers will allow you to do it, but they all interpret it differently, which is bad news bears.
333 - **Note:** ECMA-262 defines a `block` as a list of statements. A function declaration is not a statement. [Read ECMA-262's note on this issue](http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf#page=97).
334
335 ```javascript
336 // bad
337 if (currentUser) {
338 function test() {
339 console.log('Nope.');
340 }
341 }
342
343 // good
344 let test;
345 if (currentUser) {
346 test = function test() {
347 console.log('Yup.');
348 };
349 }
350 ```
351
352 - Never name a parameter `arguments`, this will take precedence over the `arguments` object that is given to every function scope.
353
354 ```javascript
355 // bad
356 function nope(name, options, arguments) {
357 // ...stuff...
358 }
359
360 // good
361 function yup(name, options, args) {
362 // ...stuff...
363 }
364 ```
365
366**[⬆ back to top](#table-of-contents)**
367
368
369
370## Properties
371
372 - Use dot notation when accessing properties.
373
374 ```javascript
375 const finn = {
376 human: true,
377 age: 28
378 };
379
380 // bad
381 const isHuman = finn['human'];
382
383 // good
384 const isHuman = finn.human;
385 ```
386
387 - Use subscript notation `[]` when accessing properties with a variable.
388
389 ```javascript
390 const finn = {
391 human: true,
392 age: 28
393 };
394
395 function getProp(prop) {
396 return finn[prop];
397 }
398
399 const isHuman = getProp('human');
400 ```
401
402**[⬆ back to top](#table-of-contents)**
403
404
405## Variables
406
407 - Always use `var` to declare variables. Not doing so will result in global variables. We want to avoid polluting the global namespace. Captain Planet warned us of that.
408
409 ```javascript
410 // bad
411 superPower = new SuperPower();
412
413 // good
414 const superPower = new SuperPower();
415 ```
416
417 - Use multiple `var` declarations for multiple variables and declare each variable on a newline.
418
419 ```javascript
420 // bad
421 const items = getItems(),
422 goSportsTeam = true,
423 dragonball = 'z';
424
425 // good
426 const items = getItems();
427 const goSportsTeam = true;
428 const dragonball = 'z';
429 ```
430
431 - Declare unassigned variables last. This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables.
432
433 ```javascript
434 // bad
435 let i, len, dragonball,
436 items = getItems(),
437 goSportsTeam = true;
438
439 // bad
440 let i;
441 const items = getItems();
442 let dragonball;
443 const goSportsTeam = true;
444 let len;
445
446 // good
447 const goSportsTeam = true;
448 const items = getItems();
449 let dragonball;
450 let i;
451 let length;
452 ```
453
454 - Assign variables at the top of their scope. This helps avoid issues with variable declaration and assignment hoisting related issues.
455
456 ```javascript
457 // bad
458 function() {
459 test();
460 console.log('doing stuff..');
461
462 //..other stuff..
463
464 const name = getName();
465
466 if (name === 'test') {
467 return false;
468 }
469
470 return name;
471 }
472
473 // good
474 function() {
475 const name = getName();
476
477 test();
478 console.log('doing stuff..');
479
480 //..other stuff..
481
482 if (name === 'test') {
483 return false;
484 }
485
486 return name;
487 }
488
489 // bad
490 function() {
491 const name = getName();
492
493 if (!arguments.length) {
494 return false;
495 }
496
497 return true;
498 }
499
500 // good
501 function() {
502 if (!arguments.length) {
503 return false;
504 }
505
506 const name = getName();
507
508 return true;
509 }
510 ```
511
512**[⬆ back to top](#table-of-contents)**
513
514
515
516## Hoisting
517
518 - [14.1](#14.1) <a name='14.1'></a> `var` declarations get hoisted to the top of their scope, their assignment does not. `const` and `let` declarations are blessed with a new concept called [Temporal Dead Zones (TDZ)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone_and_errors_with_let). It's important to know why [typeof is no longer safe](http://es-discourse.com/t/why-typeof-is-no-longer-safe/15).
519
520 ```javascript
521 // we know this wouldn't work (assuming there
522 // is no notDefined global variable)
523 function example() {
524 console.log(notDefined); // => throws a ReferenceError
525 }
526
527 // creating a variable declaration after you
528 // reference the variable will work due to
529 // variable hoisting. Note: the assignment
530 // value of `true` is not hoisted.
531 function example() {
532 console.log(declaredButNotAssigned); // => undefined
533 var declaredButNotAssigned = true;
534 }
535
536 // The interpreter is hoisting the variable
537 // declaration to the top of the scope,
538 // which means our example could be rewritten as:
539 function example() {
540 var declaredButNotAssigned;
541 console.log(declaredButNotAssigned); // => undefined
542 declaredButNotAssigned = true;
543 }
544
545 // using const and let
546 function example() {
547 console.log(declaredButNotAssigned); // => throws a ReferenceError
548 console.log(typeof declaredButNotAssigned); // => throws a ReferenceError
549 const declaredButNotAssigned = true;
550 }
551 ```
552
553 - [14.2](#14.2) <a name='14.2'></a> Anonymous function expressions hoist their variable name, but not the function assignment.
554
555 ```javascript
556 function example() {
557 console.log(anonymous); // => undefined
558
559 anonymous(); // => TypeError anonymous is not a function
560
561 var anonymous = function () {
562 console.log('anonymous function expression');
563 };
564 }
565 ```
566
567 - [14.3](#14.3) <a name='14.3'></a> Named function expressions hoist the variable name, not the function name or the function body.
568
569 ```javascript
570 function example() {
571 console.log(named); // => undefined
572
573 named(); // => TypeError named is not a function
574
575 superPower(); // => ReferenceError superPower is not defined
576
577 var named = function superPower() {
578 console.log('Flying');
579 };
580 }
581
582 // the same is true when the function name
583 // is the same as the variable name.
584 function example() {
585 console.log(named); // => undefined
586
587 named(); // => TypeError named is not a function
588
589 var named = function named() {
590 console.log('named');
591 }
592 }
593 ```
594
595 - [14.4](#14.4) <a name='14.4'></a> Function declarations hoist their name and the function body.
596
597 ```javascript
598 function example() {
599 superPower(); // => Flying
600
601 function superPower() {
602 console.log('Flying');
603 }
604 }
605 ```
606
607 - For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting/) by [Ben Cherry](http://www.adequatelygood.com/).
608
609**[⬆ back to top](#table-of-contents)**
610
611
612
613## Conditional Expressions & Equality
614
615 - Use `===` and `!==` over `==` and `!=`.
616 - Conditional expressions are evaluated using coercion with the `ToBoolean` method and always follow these simple rules:
617
618 + **Objects** evaluate to **true**
619 + **Undefined** evaluates to **false**
620 + **Null** evaluates to **false**
621 + **Booleans** evaluate to **the value of the boolean**
622 + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true**
623 + **Strings** evaluate to **false** if an empty string `''`, otherwise **true**
624
625 ```javascript
626 if ([0]) {
627 // true
628 // An array is an object, objects evaluate to true
629 }
630 ```
631
632 - Use shortcuts.
633
634 ```javascript
635 // bad
636 if (name !== '') {
637 // ...stuff...
638 }
639
640 // good
641 if (name) {
642 // ...stuff...
643 }
644
645 // bad
646 if (collection.length > 0) {
647 // ...stuff...
648 }
649
650 // good
651 if (collection.length) {
652 // ...stuff...
653 }
654 ```
655
656 - For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll
657
658 - Put your curly braces on the same line for `else` / `else if`s.
659
660 ```javascript
661 //bad
662 if (name === 'jane') {
663 // ...stuff
664 }
665 else if (name === 'bob') {
666 // ...stuff
667 }
668 else {
669 // ...stuff
670 }
671
672 //good
673 if (name === 'jane') {
674 // ...stuff
675 } else if (name === 'bob') {
676 // ...stuff
677 } else {
678 // ...stuff
679 }
680 ```
681
682**[⬆ back to top](#table-of-contents)**
683
684
685## Blocks
686
687 - Use braces. Single-line functions are okay if short. Single-line conditionals are okay if short.
688
689 ```javascript
690 // bad
691 if (test)
692 return false;
693
694 // bad
695 if (test) return false;
696
697 // good
698 if (test) { return false; }
699
700 // good
701 if (test) {
702 return false;
703 }
704
705 // good
706 function() { return false; }
707
708 // good
709 function() {
710 return false;
711 }
712 ```
713
714**[⬆ back to top](#table-of-contents)**
715
716
717## Comments
718
719 - Use `/** ... */` for docstring comments. Include a description, specify types and values for all parameters and return values.
720
721 ```javascript
722 // bad
723 // make() returns a new element
724 // based on the passed in tag name
725 //
726 // @param <String> tag
727 // @return <Element> element
728 function make(tag) {
729
730 // ...stuff...
731
732 return element;
733 }
734
735 // good
736 /**
737 * make() returns a new element
738 * based on the passed in tag name
739 *
740 * @param <String> tag
741 * @return <Element> element
742 */
743 function make(tag) {
744
745 // ...stuff...
746
747 return element;
748 }
749 ```
750
751 - Use `//` for single line comments and multi-line comments that aren't docstrings. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment.
752
753 ```javascript
754 // bad
755 const active = true; // is current tab
756
757 // good
758 // is current tab
759 const active = true;
760
761 // bad
762 function getType() {
763 console.log('fetching type...');
764 // set the default type to 'no type'
765 const type = this._type || 'no type';
766
767 return type;
768 }
769
770 // good
771 function getType() {
772 console.log('fetching type...');
773
774 // set the default type to 'no type'
775 const type = this._type || 'no type';
776
777 return type;
778 }
779 ```
780
781 - Prefixing your comments with `FIXME` or `TODO` helps other developers quickly understand if you're pointing out a problem that needs to be revisited, or if you're suggesting a solution to the problem that needs to be implemented. These are different than regular comments because they are actionable. The actions are `FIXME -- need to figure this out` or `TODO -- need to implement`.
782
783 - Use `// FIXME:` to annotate problems
784
785 ```javascript
786 function Calculator() {
787
788 // FIXME: shouldn't use a global here
789 total = 0;
790
791 return this;
792 }
793 ```
794
795 - Use `// TODO:` to annotate solutions to problems
796
797 ```javascript
798 function Calculator() {
799
800 // TODO: total should be configurable by an options param
801 this.total = 0;
802
803 return this;
804 }
805 ```
806
807**[⬆ back to top](#table-of-contents)**
808
809
810## Whitespace
811
812 - Each line should not exceed 120 characters (?)
813
814 - Use soft tabs set to 2 spaces
815
816 ```javascript
817 // bad
818 function() {
819 ∙∙∙∙const name;
820 }
821
822 // bad
823 function() {
824 ∙const name;
825 }
826
827 // good
828 function() {
829 ∙∙const name;
830 }
831 ```
832
833 - Place 1 space before the leading brace.
834
835 ```javascript
836 // bad
837 function test(){
838 console.log('test');
839 }
840
841 // good
842 function test() {
843 console.log('test');
844 }
845
846 // bad
847 dog.set('attr',{
848 age: '1 year',
849 breed: 'Bernese Mountain Dog'
850 });
851
852 // good
853 dog.set('attr', {
854 age: '1 year',
855 breed: 'Bernese Mountain Dog'
856 });
857 ```
858
859 - Set off operators with spaces.
860
861 ```javascript
862 // bad
863 const x=y+5;
864
865 // good
866 const x = y + 5;
867 ```
868
869 - Files should end with a single newline character.
870
871 ```javascript
872 // good
873 (function(global) {
874 // ...stuff...
875 })(this);↵
876 ```
877
878 ```javascript
879 // bad
880 (function(global) {
881 // ...stuff...
882 })(this);
883 ```
884
885 ```javascript
886 // bad
887 (function(global) {
888 // ...stuff...
889 })(this)↵
890 ↵
891 ```
892
893 - Use indentation when making long method chains.
894
895 ```javascript
896 // bad
897 $('#items').find('.selected').highlight().end().find('.open').updateCount();
898
899 // good
900 $('#items')
901 .find('.selected')
902 .highlight()
903 .end()
904 .find('.open')
905 .updateCount();
906
907 // bad
908 const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
909 .attr('width', (radius + margin) * 2).append('svg:g')
910 .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
911 .call(tron.led);
912
913 // good
914 const leds = stage.selectAll('.led')
915 .data(data)
916 .enter().append('svg:svg')
917 .class('led', true)
918 .attr('width', (radius + margin) * 2)
919 .append('svg:g')
920 .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
921 .call(tron.led);
922 ```
923
924**[⬆ back to top](#table-of-contents)**
925
926## Commas
927
928 - Leading commas: **Nope.**
929
930 ```javascript
931 // bad
932 const once
933 , upon
934 , aTime;
935
936 // good
937 const once = [
938 'upon',
939 'a',
940 'time'
941 ]
942
943 // bad
944 const hero = {
945 firstName: 'Bob'
946 , lastName: 'Parr'
947 , heroName: 'Mr. Incredible'
948 , superPower: 'strength'
949 };
950
951 // good
952 const hero = {
953 firstName: 'Bob',
954 lastName: 'Parr',
955 heroName: 'Mr. Incredible',
956 superPower: 'strength'
957 };
958 ```
959
960 - Additional trailing comma: **Yup.** Our Javascript is run through a compiler, and we're not terribly worried about IE < 9 support. This makes diffs cleaner. This was clarified in ES5 ([source](http://es5.github.io/#D)):
961
962 > Edition 5 clarifies the fact that a trailing comma at the end of an ArrayInitialiser does not add to the length of the array. This is not a semantic change from Edition 3 but some implementations may have previously misinterpreted this.
963
964 ```javascript
965 // bad
966 const hero = {
967 firstName: 'Kevin',
968 lastName: 'Flynn'
969 };
970
971 const heroes = [
972 'Batman',
973 'Superman'
974 ];
975
976 // good
977 const hero = {
978 firstName: 'Kevin',
979 lastName: 'Flynn',
980 };
981
982 const heroes = [
983 'Batman',
984 'Superman',
985 ];
986 ```
987
988**[⬆ back to top](#table-of-contents)**
989
990
991## Semicolons
992
993 - **Yup.**
994
995 ```javascript
996 // bad
997 (function() {
998 const name = 'Skywalker'
999 return name
1000 })()
1001
1002 // good
1003 (function() {
1004 const name = 'Skywalker';
1005 return name;
1006 })();
1007
1008 // good
1009 ;(function() {
1010 const name = 'Skywalker';
1011 return name;
1012 })();
1013 ```
1014
1015**[⬆ back to top](#table-of-contents)**
1016
1017
1018## Type Casting & Coercion
1019
1020 - Perform type coercion at the beginning of the statement.
1021 - Strings:
1022
1023 ```javascript
1024 // => this.reviewScore = 9;
1025
1026 // bad
1027 const totalScore = this.reviewScore + '';
1028
1029 // good
1030 const totalScore = '' + this.reviewScore;
1031
1032 // bad
1033 const totalScore = '' + this.reviewScore + ' total score';
1034
1035 // good
1036 const totalScore = this.reviewScore + ' total score';
1037 ```
1038
1039 - Use `parseInt` for Numbers and always with a radix for type casting.
1040
1041 ```javascript
1042 const inputValue = '4';
1043
1044 // bad
1045 const val = new Number(inputValue);
1046
1047 // bad
1048 const val = +inputValue;
1049
1050 // bad
1051 const val = inputValue >> 0;
1052
1053 // bad
1054 const val = parseInt(inputValue);
1055
1056 // good
1057 const val = Number(inputValue);
1058
1059 // good
1060 const val = parseInt(inputValue, 10);
1061 ```
1062
1063 - If for whatever reason you are doing something wild and `parseInt` is your bottleneck and need to use Bitshift for [performance reasons](http://jsperf.com/coercion-vs-casting/3), leave a comment explaining why and what you're doing.
1064 - **Note:** Be careful when using bitshift operations. Numbers are represented as [64-bit values](http://es5.github.io/#x4.3.19), but Bitshift operations always return a 32-bit integer ([source](http://es5.github.io/#x11.7)). Bitshift can lead to unexpected behavior for integer values larger than 32 bits. [Discussion](https://github.com/airbnb/javascript/issues/109)
1065
1066 ```javascript
1067 // good
1068 /**
1069 * parseInt was the reason my code was slow.
1070 * Bitshifting the String to coerce it to a
1071 * Number made it a lot faster.
1072 */
1073 const val = inputValue >> 0;
1074 ```
1075
1076 - Booleans:
1077
1078 ```javascript
1079 const age = 0;
1080
1081 // bad
1082 const hasAge = new Boolean(age);
1083
1084 // good
1085 const hasAge = Boolean(age);
1086
1087 // good
1088 const hasAge = !!age;
1089 ```
1090
1091**[⬆ back to top](#table-of-contents)**
1092
1093
1094## Naming Conventions
1095
1096 - Avoid single letter names. Be verbose with your naming.
1097
1098 ```javascript
1099 // bad
1100 function q() {
1101 // ...stuff...
1102 }
1103
1104 // good
1105 function saleQuery() {
1106 // ..stuff..
1107 }
1108 ```
1109
1110 - Use camelCase when naming objects, functions, and instances
1111
1112 ```javascript
1113 // bad
1114 const OBJEcttsssss = {};
1115 const this_is_my_object = {};
1116 function c() {};
1117 const u = new user({
1118 name: 'Bob Parr'
1119 });
1120
1121 // good
1122 const thisIsMyObject = {};
1123 function thisIsMyFunction() {};
1124 const user = new User({
1125 name: 'Bob Parr'
1126 });
1127 ```
1128
1129 - Use PascalCase when naming constructors or classes
1130
1131 ```javascript
1132 // bad
1133 function user(options) {
1134 this.name = options.name;
1135 }
1136
1137 const bad = new user({
1138 name: 'nope'
1139 });
1140
1141 // good
1142 function User(options) {
1143 this.name = options.name;
1144 }
1145
1146 const good = new User({
1147 name: 'yup'
1148 });
1149 ```
1150
1151 - Use a leading underscore `_` when naming private properties
1152
1153 ```javascript
1154 // bad
1155 this.__firstName__ = 'Panda';
1156 this.firstName_ = 'Panda';
1157
1158 // good
1159 this._firstName = 'Panda';
1160 ```
1161
1162 - When saving a reference to `this` use `_this`.
1163
1164 >Why? window.self is always available at run-time, even if you move your code or refactor it. It will be always a defined variable, no matter what, leaving you without a nice error like “ReferenceError: self is not definedâ€. Meaning that forgotten `var self = this` will be sitting as a spy in your code till the last moment before it will break.
1165
1166 ```javascript
1167 // bad
1168 function() {
1169 const self = this;
1170 return function() {
1171 console.log(self);
1172 };
1173 }
1174
1175 // bad
1176 function() {
1177 const that = this;
1178 return function() {
1179 console.log(that);
1180 };
1181 }
1182
1183 // good
1184 function() {
1185 const _this = this;
1186 return function() {
1187 console.log(_this);
1188 };
1189 }
1190 ```
1191
1192 - Name your functions. This is helpful for stack traces.
1193
1194 ```javascript
1195 // bad
1196 const log = function(msg) {
1197 console.log(msg);
1198 };
1199
1200 // good
1201 const log = function log(msg) {
1202 console.log(msg);
1203 };
1204 ```
1205
1206**[⬆ back to top](#table-of-contents)**
1207
1208
1209## Accessors
1210
1211 - Accessor functions for properties are not required
1212 - If you do make accessor functions use getVal() and setVal('hello')
1213
1214 ```javascript
1215 // bad
1216 dragon.age();
1217
1218 // good
1219 dragon.getAge();
1220
1221 // bad
1222 dragon.age(25);
1223
1224 // good
1225 dragon.setAge(25);
1226 ```
1227
1228 - If the property is a boolean, use isVal() or hasVal()
1229
1230 ```javascript
1231 // bad
1232 if (!dragon.age()) {
1233 return false;
1234 }
1235
1236 // good
1237 if (!dragon.hasAge()) {
1238 return false;
1239 }
1240 ```
1241
1242 - It's okay to create get() and set() functions, but be consistent.
1243
1244 ```javascript
1245 function Jedi(options) {
1246 options || (options = {});
1247 const lightsaber = options.lightsaber || 'blue';
1248 this.set('lightsaber', lightsaber);
1249 }
1250
1251 Jedi.prototype.set = function(key, val) {
1252 this[key] = val;
1253 };
1254
1255 Jedi.prototype.get = function(key) {
1256 return this[key];
1257 };
1258 ```
1259
1260**[⬆ back to top](#table-of-contents)**
1261
1262
1263## Constructors
1264
1265 - Assign methods to the prototype object, instead of overwriting the prototype with a new object. Overwriting the prototype makes inheritance impossible: by resetting the prototype you'll overwrite the base!
1266
1267 ```javascript
1268 function Jedi() {
1269 console.log('new jedi');
1270 }
1271
1272 // bad
1273 Jedi.prototype = {
1274 fight: function fight() {
1275 console.log('fighting');
1276 },
1277
1278 block: function block() {
1279 console.log('blocking');
1280 }
1281 };
1282
1283 // good
1284 Jedi.prototype.fight = function fight() {
1285 console.log('fighting');
1286 };
1287
1288 Jedi.prototype.block = function block() {
1289 console.log('blocking');
1290 };
1291 ```
1292
1293 - Methods can return `this` to help with method chaining.
1294
1295 ```javascript
1296 // bad
1297 Jedi.prototype.jump = function() {
1298 this.jumping = true;
1299 return true;
1300 };
1301
1302 Jedi.prototype.setHeight = function(height) {
1303 this.height = height;
1304 };
1305
1306 const luke = new Jedi();
1307 luke.jump(); // => true
1308 luke.setHeight(20) // => undefined
1309
1310 // good
1311 Jedi.prototype.jump = function() {
1312 this.jumping = true;
1313 return this;
1314 };
1315
1316 Jedi.prototype.setHeight = function(height) {
1317 this.height = height;
1318 return this;
1319 };
1320
1321 const luke = new Jedi();
1322
1323 luke.jump()
1324 .setHeight(20);
1325 ```
1326
1327
1328 - It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects.
1329
1330 ```javascript
1331 function Jedi(options) {
1332 options || (options = {});
1333 this.name = options.name || 'no name';
1334 }
1335
1336 Jedi.prototype.getName = function getName() {
1337 return this.name;
1338 };
1339
1340 Jedi.prototype.toString = function toString() {
1341 return 'Jedi - ' + this.getName();
1342 };
1343 ```
1344
1345**[⬆ back to top](#table-of-contents)**
1346
1347
1348## Events
1349
1350 - When attaching data payloads to events (whether DOM events or something more proprietary like Backbone events), pass a hash instead of a raw value. This allows a subsequent contributor to add more data to the event payload without finding and updating every handler for the event. For example, instead of:
1351
1352 ```js
1353 // bad
1354 $(this).trigger('listingUpdated', listing.id);
1355
1356 ...
1357
1358 $(this).on('listingUpdated', function(e, listingId) {
1359 // do something with listingId
1360 });
1361 ```
1362
1363 prefer:
1364
1365 ```js
1366 // good
1367 $(this).trigger('listingUpdated', { listingId : listing.id });
1368
1369 ...
1370
1371 $(this).on('listingUpdated', function(e, data) {
1372 // do something with data.listingId
1373 });
1374 ```
1375
1376 - For event handlers, prefix with "on" and use the present tense. Prefer "on" + eventName, but if ambiguous other words may be used.
1377
1378 ```js
1379 // bad
1380 this.listenTo(this.model, 'add', this.added)
1381
1382 // good
1383 this.listenTo(this.model, 'add', this.onAdd)
1384
1385 // also good
1386 this.listenTo(this.model, 'add', this.onAddItem)
1387 ```
1388
1389 **[⬆ back to top](#table-of-contents)**
1390
1391## Promises
1392
1393 - Errors must be handled by either throw or catch. Do not forget to provide an error handling routine, and do not return undefined. Thus, we should use a common promises library on top of $http (which does not follow the open promises standard at all). (?)
1394
1395 ```js
1396 // bad: no error handling
1397 $http({
1398 method: 'GET',
1399 url: '/someUrl'
1400 }).then(function successCallback(response) {
1401 return handleSuccess(response);
1402 });
1403
1404 // bad: return undefined;
1405 $http({
1406 method: 'GET',
1407 url: '/someUrl'
1408 }).then(function successCallback(response) {
1409 return handleSuccess(response);
1410 }, function errorCallback(error) {
1411 return undefined;
1412 });
1413
1414 // good
1415 $http({
1416 method: 'GET',
1417 url: '/someUrl'
1418 }).then(function successCallback(response) {
1419 return handleSuccess(response);
1420 }, function errorCallback(error) {
1421 //maybe log the error here as well
1422 return handleError(response);
1423 });
1424 ```
1425
1426 - For event handlers, prefix with "on" and use the present tense. Prefer "on" + eventName, but if ambiguous other words may be used.
1427
1428 ```js
1429 // bad
1430 this.listenTo(this.model, 'add', this.added)
1431
1432 // good
1433 this.listenTo(this.model, 'add', this.onAdd)
1434
1435 // also good
1436 this.listenTo(this.model, 'add', this.onAddItem)
1437 ```
1438
1439 **[⬆ back to top](#table-of-contents)**
1440
1441
1442## Modules
1443
1444 - The module should start with a `!`. This ensures that if a malformed module forgets to include a final semicolon there aren't errors in production when the scripts get concatenated. [Explanation](https://github.com/airbnb/javascript/issues/44#issuecomment-13063933)
1445 - The file should be named with camelCase, live in a folder with the same name, and match the name of the single export.
1446 - Add a method called noConflict() that sets the exported module to the previous version and returns this one.
1447 - Always declare `'use strict';` at the top of the module.
1448
1449 ```javascript
1450 // fancyInput/fancyInput.js
1451
1452 !function(global) {
1453 'use strict';
1454
1455 const previousFancyInput = global.FancyInput;
1456
1457 function FancyInput(options) {
1458 this.options = options || {};
1459 }
1460
1461 FancyInput.noConflict = function noConflict() {
1462 global.FancyInput = previousFancyInput;
1463 return FancyInput;
1464 };
1465
1466 global.FancyInput = FancyInput;
1467 }(this);
1468 ```
1469
1470**[⬆ back to top](#table-of-contents)**
1471
1472
1473## jQuery
1474
1475 - Prefix jQuery object variables with a `$`.
1476
1477 ```javascript
1478 // bad
1479 const sidebar = $('.sidebar');
1480
1481 // good
1482 const $sidebar = $('.sidebar');
1483 ```
1484
1485 - Cache jQuery lookups.
1486
1487 ```javascript
1488 // bad
1489 function setSidebar() {
1490 $('.sidebar').hide();
1491
1492 // ...stuff...
1493
1494 $('.sidebar').css({
1495 'background-color': 'pink'
1496 });
1497 }
1498
1499 // good
1500 function setSidebar() {
1501 const $sidebar = $('.sidebar');
1502 $sidebar.hide();
1503
1504 // ...stuff...
1505
1506 $sidebar.css({
1507 'background-color': 'pink'
1508 });
1509 }
1510 ```
1511
1512 - For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
1513 - Use `find` with scoped jQuery object queries.
1514
1515 ```javascript
1516 // bad
1517 $('ul', '.sidebar').hide();
1518
1519 // bad
1520 $('.sidebar').find('ul').hide();
1521
1522 // good
1523 $('.sidebar ul').hide();
1524
1525 // good
1526 $('.sidebar > ul').hide();
1527
1528 // good
1529 $sidebar.find('ul').hide();
1530 ```
1531
1532**[⬆ back to top](#table-of-contents)**
1533
1534
1535## ECMAScript 5 Compatibility
1536
1537 - The ecmascript5 shim is available. Prefer ES5 methods when it makes sense..
1538
1539**[⬆ back to top](#table-of-contents)**
1540
1541
1542## Testing
1543
1544 - **Yup.**
1545
1546 ```javascript
1547 function() {
1548 return true;
1549 }
1550 ```
1551
1552**[⬆ back to top](#table-of-contents)**
1553
1554
1555## Performance
1556
1557 - [On Layout & Web Performance](http://kellegous.com/j/2013/01/26/layout-performance/)
1558 - [String vs Array Concat](http://jsperf.com/string-vs-array-concat/2)
1559 - [Try/Catch Cost In a Loop](http://jsperf.com/try-catch-in-loop-cost)
1560 - [Bang Function](http://jsperf.com/bang-function)
1561 - [jQuery Find vs Context, Selector](http://jsperf.com/jquery-find-vs-context-sel/13)
1562 - [innerHTML vs textContent for script text](http://jsperf.com/innerhtml-vs-textcontent-for-script-text)
1563 - [Long String Concatenation](http://jsperf.com/ya-string-concat)
1564 - Loading...
1565
1566**[⬆ back to top](#table-of-contents)**
1567
1568
1569## Resources
1570
1571
1572**Read This**
1573
1574 - [Annotated ECMAScript 5.1](http://es5.github.com/)
1575
1576**Other Styleguides**
1577
1578 - This was adapted from the [Airbnb Javascript Style Guide](https://github.com/airbnb/javascript)
1579 - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml)
1580 - [jQuery Core Style Guidelines](http://docs.jquery.com/JQuery_Core_Style_Guidelines)
1581 - [Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwldrn/idiomatic.js/)
1582
1583**Other Styles**
1584
1585 - [Naming this in nested functions](https://gist.github.com/4135065) - Christian Johansen
1586 - [Conditional Callbacks](https://github.com/airbnb/javascript/issues/52)
1587 - [Popular JavaScript Coding Conventions on Github](http://sideeffect.kr/popularconvention/#javascript)
1588
1589**Further Reading**
1590
1591 - [Understanding JavaScript Closures](http://javascriptweblog.wordpress.com/2010/10/25/understanding-javascript-closures/) - Angus Croll
1592 - [Basic JavaScript for the impatient programmer](http://www.2ality.com/2013/06/basic-javascript.html) - Dr. Axel Rauschmayer
1593 - [You Might Not Need jQuery](http://youmightnotneedjquery.com/) - Zack Bloom & Adam Schwartz
1594 - [ES6 Features](https://github.com/lukehoban/es6features) - Luke Hoban
1595
1596**Books**
1597
1598 - [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) - Douglas Crockford
1599 - [JavaScript Patterns](http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752) - Stoyan Stefanov
1600 - [Pro JavaScript Design Patterns](http://www.amazon.com/JavaScript-Design-Patterns-Recipes-Problem-Solution/dp/159059908X) - Ross Harmes and Dustin Diaz
1601 - [High Performance Web Sites: Essential Knowledge for Front-End Engineers](http://www.amazon.com/High-Performance-Web-Sites-Essential/dp/0596529309) - Steve Souders
1602 - [Maintainable JavaScript](http://www.amazon.com/Maintainable-JavaScript-Nicholas-C-Zakas/dp/1449327680) - Nicholas C. Zakas
1603 - [JavaScript Web Applications](http://www.amazon.com/JavaScript-Web-Applications-Alex-MacCaw/dp/144930351X) - Alex MacCaw
1604 - [Pro JavaScript Techniques](http://www.amazon.com/Pro-JavaScript-Techniques-John-Resig/dp/1590597273) - John Resig
1605 - [Smashing Node.js: JavaScript Everywhere](http://www.amazon.com/Smashing-Node-js-JavaScript-Everywhere-Magazine/dp/1119962595) - Guillermo Rauch
1606 - [Secrets of the JavaScript Ninja](http://www.amazon.com/Secrets-JavaScript-Ninja-John-Resig/dp/193398869X) - John Resig and Bear Bibeault
1607 - [Human JavaScript](http://humanjavascript.com/) - Henrik Joreteg
1608 - [Superhero.js](http://superherojs.com/) - Kim Joar Bekkelund, Mads Mobæk, & Olav Bjorkoy
1609 - [JSBooks](http://jsbooks.revolunet.com/)
1610 - [Third Party JavaScript](http://manning.com/vinegar/) - Ben Vinegar and Anton Kovalyov
1611
1612**Blogs**
1613
1614 - [DailyJS](http://dailyjs.com/)
1615 - [JavaScript Weekly](http://javascriptweekly.com/)
1616 - [JavaScript, JavaScript...](http://javascriptweblog.wordpress.com/)
1617 - [Bocoup Weblog](http://weblog.bocoup.com/)
1618 - [Adequately Good](http://www.adequatelygood.com/)
1619 - [NCZOnline](http://www.nczonline.net/)
1620 - [Perfection Kills](http://perfectionkills.com/)
1621 - [Ben Alman](http://benalman.com/)
1622 - [Dmitry Baranovskiy](http://dmitry.baranovskiy.com/)
1623 - [Dustin Diaz](http://dustindiaz.com/)
1624 - [nettuts](http://net.tutsplus.com/?s=javascript)
1625
1626**[⬆ back to top](#table-of-contents)**
1627
1628## License
1629
1630(The MIT License)
1631
1632Copyright (c) 2016 ClockCrew
1633
1634Permission is hereby granted, free of charge, to any person obtaining
1635a copy of this software and associated documentation files (the
1636'Software'), to deal in the Software without restriction, including
1637without limitation the rights to use, copy, modify, merge, publish,
1638distribute, sublicense, and/or sell copies of the Software, and to
1639permit persons to whom the Software is furnished to do so, subject to
1640the following conditions:
1641
1642The above copyright notice and this permission notice shall be
1643included in all copies or substantial portions of the Software.
1644
1645THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
1646EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1647MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1648IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1649CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1650TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1651SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1652
1653**[⬆ back to top](#table-of-contents)**
1654
1655# };