├── .gitignore
├── README.md
├── es5
└── README.md
├── linters
├── .eslintrc
├── README.md
├── SublimeLinter
│ └── SublimeLinter.sublime-settings
└── jshintrc
├── package.json
├── packages
└── eslint-config-airbnb
│ ├── index.js
│ └── package.json
└── react
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
2 |
3 | # Airbnb JavaScript Style Guide, Meteor edition
4 |
5 | *A mostly reasonable approach to JavaScript, with some Meteor flavor*
6 |
7 | All rules that are automatically linted have the ESLint logo, with a link to the rule, like so:
8 |
9 | ## Table of Contents
10 |
11 | 1. [Types](#types)
12 | 1. [References](#references)
13 | 1. [Objects](#objects)
14 | 1. [Arrays](#arrays)
15 | 1. [Destructuring](#destructuring)
16 | 1. [Strings](#strings)
17 | 1. [Functions](#functions)
18 | 1. [Arrow Functions](#arrow-functions)
19 | 1. [Constructors](#constructors)
20 | 1. [Modules](#modules)
21 | 1. [Iterators and Generators](#iterators-and-generators)
22 | 1. [Properties](#properties)
23 | 1. [Variables](#variables)
24 | 1. [Hoisting](#hoisting)
25 | 1. [Comparison Operators & Equality](#comparison-operators--equality)
26 | 1. [Blocks](#blocks)
27 | 1. [Comments](#comments)
28 | 1. [Whitespace](#whitespace)
29 | 1. [Commas](#commas)
30 | 1. [Semicolons](#semicolons)
31 | 1. [Type Casting & Coercion](#type-casting--coercion)
32 | 1. [Naming Conventions](#naming-conventions)
33 | 1. [Accessors](#accessors)
34 | 1. [Events](#events)
35 | 1. [jQuery](#jquery)
36 | 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility)
37 | 1. [ECMAScript 6 Styles](#ecmascript-6-styles)
38 | 1. [Testing (in AirBnB guide)](https://github.com/airbnb/javascript#testing)
39 | 1. [Performance (in AirBnB guide)](https://github.com/airbnb/javascript#performance)
40 | 1. [Resources (in AirBnB guide)](https://github.com/airbnb/javascript#resources)
41 | 1. [In the Wild (in AirBnB guide)](https://github.com/airbnb/javascript#in-the-wild)
42 | 1. [Translation (in AirBnB guide)](https://github.com/airbnb/javascript#translation)
43 | 1. [The JavaScript Style Guide Guide (in AirBnB guide)](https://github.com/airbnb/javascript#the-javascript-style-guide-guide)
44 | 1. [Chat With Us About Javascript (in AirBnB guide)](https://github.com/airbnb/javascript#chat-with-us-about-javascript)
45 | 1. [Contributors](#contributors)
46 | 1. [License](#license)
47 |
48 | ## Types
49 |
50 | This section has been eliminated in the Meteor version, because it does not specify any style rules.
51 |
52 | ## References
53 |
54 | - [2.1](#2.1)
55 | Use `const` for all of your references; avoid using `var`.
56 |
57 | > Why? This ensures that you can't reassign your references (mutation), which can lead to bugs and difficult to comprehend code.
58 |
59 | ```javascript
60 | // bad
61 | var a = 1;
62 | var b = 2;
63 |
64 | // good
65 | const a = 1;
66 | const b = 2;
67 | ```
68 |
69 | - [2.2](#2.2)
70 | If you must mutate references, use `let` instead of `var`.
71 |
72 | > Why? `let` is block-scoped rather than function-scoped like `var`.
73 |
74 | ```javascript
75 | // bad
76 | var count = 1;
77 | if (true) {
78 | count += 1;
79 | }
80 |
81 | // good, use the let.
82 | let count = 1;
83 | if (true) {
84 | count += 1;
85 | }
86 | ```
87 |
88 | - [2.3](#2.3) This section removed in the Meteor edition, because it does not specify any style rules.
89 |
90 | **[⬆ back to top](#table-of-contents)**
91 |
92 | ## Objects
93 |
94 | - [3.1](#3.1)
95 | Use the literal syntax for object creation.
96 |
97 | ```javascript
98 | // bad
99 | const item = new Object();
100 |
101 | // good
102 | const item = {};
103 | ```
104 |
105 | - [3.2](#3.2) and [3.3](#3.3) eliminated in the Meteor edition because Babel can compile reserved words to work fine in old browsers.
106 |
107 |
108 | - [3.4](#3.4) Use computed property names when creating objects with dynamic property names.
109 |
110 | > Why? They allow you to define all the properties of an object in one place.
111 |
112 | ```javascript
113 |
114 | function getKey(k) {
115 | return `a key named ${k}`;
116 | }
117 |
118 | // bad
119 | const obj = {
120 | id: 5,
121 | name: 'San Francisco',
122 | };
123 | obj[getKey('enabled')] = true;
124 |
125 | // good
126 | const obj = {
127 | id: 5,
128 | name: 'San Francisco',
129 | [getKey('enabled')]: true,
130 | };
131 | ```
132 |
133 |
134 | - [3.5](#3.5) Use object method shorthand.
135 |
136 | ```javascript
137 | // bad
138 | const atom = {
139 | value: 1,
140 |
141 | addValue: function (value) {
142 | return atom.value + value;
143 | },
144 | };
145 |
146 | // good
147 | const atom = {
148 | value: 1,
149 |
150 | addValue(value) {
151 | return atom.value + value;
152 | },
153 | };
154 | ```
155 |
156 |
157 | - [3.6](#3.6) Use property value shorthand.
158 |
159 | > Why? It is shorter to write and descriptive.
160 |
161 | ```javascript
162 | const lukeSkywalker = 'Luke Skywalker';
163 |
164 | // bad
165 | const obj = {
166 | lukeSkywalker: lukeSkywalker,
167 | };
168 |
169 | // good
170 | const obj = {
171 | lukeSkywalker,
172 | };
173 | ```
174 |
175 | - [3.7](#3.7) Group your shorthand properties at the beginning of your object declaration.
176 |
177 | > Why? It's easier to tell which properties are using the shorthand.
178 |
179 | ```javascript
180 | const anakinSkywalker = 'Anakin Skywalker';
181 | const lukeSkywalker = 'Luke Skywalker';
182 |
183 | // bad
184 | const obj = {
185 | episodeOne: 1,
186 | twoJedisWalkIntoACantina: 2,
187 | lukeSkywalker,
188 | episodeThree: 3,
189 | mayTheFourth: 4,
190 | anakinSkywalker,
191 | };
192 |
193 | // good
194 | const obj = {
195 | lukeSkywalker,
196 | anakinSkywalker,
197 | episodeOne: 1,
198 | twoJedisWalkIntoACantina: 2,
199 | episodeThree: 3,
200 | mayTheFourth: 4,
201 | };
202 | ```
203 |
204 | - [3.8](#3.8) Use object spreads `...` to copy objects.
205 |
206 | ```javascript
207 | // bad
208 | const copy = {};
209 | Object.keys(obj).forEach((key) => {
210 | copy[key] = obj[key];
211 | });
212 |
213 | // bad
214 | const copy = {};
215 | for (var key in obj) {
216 | if (Object.prototype.hasOwnProperty.call(obj, key)) {
217 | copy[key] = obj[key];
218 | }
219 | }
220 |
221 | // good
222 | const copy = { ...obj };
223 | ```
224 |
225 | **[⬆ back to top](#table-of-contents)**
226 |
227 | ## Arrays
228 |
229 | - [4.1](#4.1)
230 | Use the literal syntax for array creation.
231 |
232 | ```javascript
233 | // bad
234 | const items = new Array();
235 |
236 | // good
237 | const items = [];
238 | ```
239 |
240 | - [4.2](#4.2) Use Array#push instead of direct assignment to add items to an array.
241 |
242 | ```javascript
243 | const someStack = [];
244 |
245 |
246 | // bad
247 | someStack[someStack.length] = 'abracadabra';
248 |
249 | // good
250 | someStack.push('abracadabra');
251 | ```
252 |
253 |
254 | - [4.3](#4.3) Use array spreads `...` to copy arrays.
255 |
256 | ```javascript
257 | // bad
258 | const len = items.length;
259 | const itemsCopy = [];
260 | let i;
261 |
262 | for (i = 0; i < len; i++) {
263 | itemsCopy[i] = items[i];
264 | }
265 |
266 | // good
267 | const itemsCopy = [...items];
268 | ```
269 | - [4.4](#4.4) To convert an array-like object to an array, use Array#from.
270 |
271 | ```javascript
272 | const foo = document.querySelectorAll('.foo');
273 | const nodes = Array.from(foo);
274 | ```
275 |
276 | **[⬆ back to top](#table-of-contents)**
277 |
278 | ## Destructuring
279 |
280 | - [5.1](#5.1) Use object destructuring when accessing and using multiple properties of an object.
281 |
282 | > Why? Destructuring saves you from creating temporary references for those properties.
283 |
284 | ```javascript
285 | // bad
286 | function getFullName(user) {
287 | const firstName = user.firstName;
288 | const lastName = user.lastName;
289 |
290 | return `${firstName} ${lastName}`;
291 | }
292 |
293 | // good
294 | function getFullName(obj) {
295 | const { firstName, lastName } = obj;
296 | return `${firstName} ${lastName}`;
297 | }
298 |
299 | // best
300 | function getFullName({ firstName, lastName }) {
301 | return `${firstName} ${lastName}`;
302 | }
303 | ```
304 |
305 | - [5.2](#5.2) Use array destructuring.
306 |
307 | ```javascript
308 | const arr = [1, 2, 3, 4];
309 |
310 | // bad
311 | const first = arr[0];
312 | const second = arr[1];
313 |
314 | // good
315 | const [first, second] = arr;
316 | ```
317 |
318 | - [5.3](#5.3) Use object destructuring for multiple return values, not array destructuring.
319 |
320 | > Why? You can add new properties over time or change the order of things without breaking call sites.
321 |
322 | ```javascript
323 | // bad
324 | function processInput(input) {
325 | // then a miracle occurs
326 | return [left, right, top, bottom];
327 | }
328 |
329 | // the caller needs to think about the order of return data
330 | const [left, __, top] = processInput(input);
331 |
332 | // good
333 | function processInput(input) {
334 | // then a miracle occurs
335 | return { left, right, top, bottom };
336 | }
337 |
338 | // the caller selects only the data they need
339 | const { left, right } = processInput(input);
340 | ```
341 |
342 |
343 | **[⬆ back to top](#table-of-contents)**
344 |
345 | ## Strings
346 |
347 | - [6.1](#6.1)
348 | Use single quotes `''` for strings.
349 |
350 | ```javascript
351 | // bad
352 | const name = "Capt. Janeway";
353 |
354 | // good
355 | const name = 'Capt. Janeway';
356 | ```
357 |
358 | - [6.2](#6.2)
359 | Single-line strings longer than 80 characters should be written across multiple lines using string concatenation. If you are writing a multiline string, use template strings as in [6.4](#6.4). This is a change in the Meteor edition. 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).
360 |
361 | ```javascript
362 | // bad
363 | 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.';
364 |
365 | // bad
366 | const errorMessage = 'This is a super long error that was thrown because \
367 | of Batman. When you stop to think about how Batman had anything to do \
368 | with this, you would get nowhere \
369 | fast.';
370 |
371 | // good
372 | const errorMessage = 'This is a super long error that was thrown because ' +
373 | 'of Batman. When you stop to think about how Batman had anything to do ' +
374 | 'with this, you would get nowhere fast.';
375 | ```
376 |
377 | - [6.3](#6.3) This non-rule merged as a note into the previous rule in the Meteor edition.
378 |
379 |
380 | - [6.4](#6.4) When programmatically building up strings, use template strings instead of concatenation.
381 |
382 | > Why? Template strings give you a readable, concise syntax with proper newlines and string interpolation features.
383 |
384 | ```javascript
385 | // bad
386 | function sayHi(name) {
387 | return 'How are you, ' + name + '?';
388 | }
389 |
390 | // bad
391 | function sayHi(name) {
392 | return ['How are you, ', name, '?'].join();
393 | }
394 |
395 | // good
396 | function sayHi(name) {
397 | return `How are you, ${name}?`;
398 | }
399 | ```
400 |
401 | **[⬆ back to top](#table-of-contents)**
402 |
403 |
404 | ## Functions
405 |
406 | - [7.1](#7.1)
407 | Use function declarations instead of function expressions.
408 |
409 | > Why? Function declarations are named, so they're easier to identify in call stacks. Also, the whole body of a function declaration is hoisted, whereas only the reference of a function expression is hoisted. This rule makes it possible to always use [Arrow Functions](#arrow-functions) in place of function expressions.
410 |
411 | ```javascript
412 | // bad
413 | const foo = function () {
414 | };
415 |
416 | // good
417 | function foo() {
418 | }
419 | ```
420 |
421 | - [7.2](#7.2) Removed in the Meteor edition.
422 | - [7.3](#7.3)
423 | 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. [7.4](#7.4) **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). This note merged into the previous rule in the Meteor edition.
424 |
425 | ```javascript
426 | // bad
427 | if (currentUser) {
428 | function test() {
429 | console.log('Nope.');
430 | }
431 | }
432 |
433 | // good
434 | let test;
435 | if (currentUser) {
436 | test = () => {
437 | console.log('Yup.');
438 | };
439 | }
440 | ```
441 |
442 | - [7.5](#7.5)
443 | Never name a parameter `arguments`. This will take precedence over the `arguments` object that is given to every function scope.
444 |
445 | ```javascript
446 | // bad
447 | function nope(name, options, arguments) {
448 | // ...stuff...
449 | }
450 |
451 | // good
452 | function yup(name, options, args) {
453 | // ...stuff...
454 | }
455 | ```
456 |
457 |
458 | - [7.6](#7.6) Never use `arguments`, opt to use rest syntax `...` instead.
459 |
460 | > Why? `...` is explicit about which arguments you want pulled. Plus rest arguments are a real Array and not Array-like like `arguments`.
461 |
462 | ```javascript
463 | // bad
464 | function concatenateAll() {
465 | const args = Array.prototype.slice.call(arguments);
466 | return args.join('');
467 | }
468 |
469 | // good
470 | function concatenateAll(...args) {
471 | return args.join('');
472 | }
473 | ```
474 |
475 |
476 | - [7.7](#7.7) Use default parameter syntax rather than mutating function arguments.
477 |
478 | ```javascript
479 | // really bad
480 | function handleThings(opts) {
481 | // No! We shouldn't mutate function arguments.
482 | // Double bad: if opts is falsy it'll be set to an object which may
483 | // be what you want but it can introduce subtle bugs.
484 | opts = opts || {};
485 | // ...
486 | }
487 |
488 | // still bad
489 | function handleThings(opts) {
490 | if (opts === void 0) {
491 | opts = {};
492 | }
493 | // ...
494 | }
495 |
496 | // good
497 | function handleThings(opts = {}) {
498 | // ...
499 | }
500 | ```
501 |
502 | - [7.8](#7.8) Avoid side effects with default parameters
503 |
504 | > Why? They are confusing to reason about.
505 |
506 | ```javascript
507 | var b = 1;
508 | // bad
509 | function count(a = b++) {
510 | console.log(a);
511 | }
512 | count(); // 1
513 | count(); // 2
514 | count(3); // 3
515 | count(); // 3
516 | ```
517 |
518 | - [7.9](#7.9) Use argument spreads to interpolate
519 | arguments in function calls.
520 |
521 | ```javascript
522 | const prefix = [a, b];
523 | const suffix = [c, d, e];
524 |
525 | // bad
526 | prefix.push.apply(prefix, suffix);
527 |
528 | // good
529 | prefix.push(...suffix);
530 |
531 | // bad
532 | someFunction.apply(null, prefix.concat(suffix));
533 |
534 | // good
535 | someFunction(...prefix, ...suffix);
536 | ```
537 |
538 | The exception to this advice is when you really need to use a
539 | different, non-`null` value of `this`. Then `.apply` (or `.call`) is
540 | probably a better option.
541 |
542 | The same goes for `new` expressions.
543 |
544 | ```javascript
545 | class A {
546 | constructor(...args) { ... }
547 | }
548 |
549 | // really bad
550 | const instance = Object.create(A.prototype);
551 | A.prototype.constructor.apply(instance, prefix.concat(suffix));
552 |
553 | // good
554 | const instance = new A(...prefix, ...suffix);
555 | ```
556 |
557 | **[⬆ back to top](#table-of-contents)**
558 |
559 | ## Arrow Functions
560 |
561 | - [8.1](#8.1) When you must use function expressions (as when passing an anonymous function), use arrow function notation.
562 |
563 | > Why? It creates a version of the function that executes in the context of `this`, which is usually what you want, and is a more concise syntax.
564 |
565 | > Why not? If you have a fairly complicated function, you might move that logic out into its own function declaration.
566 |
567 | ```javascript
568 | // bad
569 | [1, 2, 3].map(function (x) {
570 | return x * x;
571 | });
572 |
573 | // good
574 | [1, 2, 3].map((x) => {
575 | return x * x;
576 | });
577 | ```
578 |
579 | - [8.2](#8.2) If the function body fits on one line and there is only a single argument, feel free to omit the braces and parentheses, and use the implicit return. Otherwise, add the parentheses, braces, and use a `return` statement.
580 |
581 | > Why? Syntactic sugar. It reads well when multiple functions are chained together.
582 |
583 | > Why not? If you plan on returning an object.
584 |
585 | ```javascript
586 | // good
587 | [1, 2, 3].map(x => x * x);
588 |
589 | // good
590 | [1, 2, 3].reduce((total, n) => {
591 | return total + n;
592 | }, 0);
593 | ```
594 |
595 | **[⬆ back to top](#table-of-contents)**
596 |
597 |
598 | ## Constructors
599 |
600 | - [9.1](#9.1) Always use `class`. Avoid manipulating `prototype` directly.
601 |
602 | > Why? `class` syntax is more concise and easier to reason about.
603 |
604 | ```javascript
605 | // bad
606 | function Queue(contents = []) {
607 | this._queue = [...contents];
608 | }
609 | Queue.prototype.pop = function() {
610 | const value = this._queue[0];
611 | this._queue.splice(0, 1);
612 | return value;
613 | }
614 |
615 |
616 | // good
617 | class Queue {
618 | constructor(contents = []) {
619 | this._queue = [...contents];
620 | }
621 | pop() {
622 | const value = this._queue[0];
623 | this._queue.splice(0, 1);
624 | return value;
625 | }
626 | }
627 | ```
628 |
629 | - [9.2](#9.2) Use `extends` for inheritance.
630 |
631 | > Why? It is a built-in way to inherit prototype functionality without breaking `instanceof`.
632 |
633 | ```javascript
634 | // bad
635 | const inherits = require('inherits');
636 | function PeekableQueue(contents) {
637 | Queue.apply(this, contents);
638 | }
639 | inherits(PeekableQueue, Queue);
640 | PeekableQueue.prototype.peek = function() {
641 | return this._queue[0];
642 | }
643 |
644 | // good
645 | class PeekableQueue extends Queue {
646 | peek() {
647 | return this._queue[0];
648 | }
649 | }
650 | ```
651 |
652 | - [9.3](#9.3) Methods can return `this` to help with method chaining.
653 |
654 | ```javascript
655 | // bad
656 | Jedi.prototype.jump = function() {
657 | this.jumping = true;
658 | return true;
659 | };
660 |
661 | Jedi.prototype.setHeight = function(height) {
662 | this.height = height;
663 | };
664 |
665 | const luke = new Jedi();
666 | luke.jump(); // => true
667 | luke.setHeight(20); // => undefined
668 |
669 | // good
670 | class Jedi {
671 | jump() {
672 | this.jumping = true;
673 | return this;
674 | }
675 |
676 | setHeight(height) {
677 | this.height = height;
678 | return this;
679 | }
680 | }
681 |
682 | const luke = new Jedi();
683 |
684 | luke.jump()
685 | .setHeight(20);
686 | ```
687 |
688 |
689 | - [9.4](#9.4) It's okay to write a custom toString() method, just make sure it works successfully and causes no side effects.
690 |
691 | ```javascript
692 | class Jedi {
693 | contructor(options = {}) {
694 | this.name = options.name || 'no name';
695 | }
696 |
697 | getName() {
698 | return this.name;
699 | }
700 |
701 | toString() {
702 | return `Jedi - ${this.getName()}`;
703 | }
704 | }
705 | ```
706 |
707 | **[⬆ back to top](#table-of-contents)**
708 |
709 |
710 | ## Modules
711 |
712 | - [10.1](#10.1) Always use modules (`import`/`export`) over a non-standard module system. You can always transpile to your preferred module system.
713 |
714 | > Why? Modules are the future, let's start using the future now.
715 |
716 | ```javascript
717 | // bad
718 | const AirbnbStyleGuide = require('./AirbnbStyleGuide');
719 | module.exports = AirbnbStyleGuide.es6;
720 |
721 | // ok
722 | import AirbnbStyleGuide from './AirbnbStyleGuide';
723 | export default AirbnbStyleGuide.es6;
724 |
725 | // best
726 | import { es6 } from './AirbnbStyleGuide';
727 | export default es6;
728 | ```
729 |
730 | - [10.2](#10.2) Do not use wildcard imports.
731 |
732 | > Why? This makes sure you have a single default export.
733 |
734 | ```javascript
735 | // bad
736 | import * as AirbnbStyleGuide from './AirbnbStyleGuide';
737 |
738 | // good
739 | import AirbnbStyleGuide from './AirbnbStyleGuide';
740 | ```
741 |
742 | - [10.3](#10.3) And do not export directly from an import.
743 |
744 | > Why? Although the one-liner is concise, having one clear way to import and one clear way to export makes things consistent.
745 |
746 | ```javascript
747 | // bad
748 | // filename es6.js
749 | export { es6 as default } from './airbnbStyleGuide';
750 |
751 | // good
752 | // filename es6.js
753 | import { es6 } from './AirbnbStyleGuide';
754 | export default es6;
755 | ```
756 |
757 | **[⬆ back to top](#table-of-contents)**
758 |
759 | ## Iterators and Generators
760 |
761 | - [11.1](#11.1) Don't use iterators. Prefer JavaScript's higher-order functions like `map()` and `reduce()` instead of loops like `for-of`.
762 |
763 | > Why? This enforces our immutable rule. Dealing with pure functions that return values is easier to reason about than side-effects.
764 |
765 | ```javascript
766 | const numbers = [1, 2, 3, 4, 5];
767 |
768 | // bad
769 | let sum = 0;
770 | for (let num of numbers) {
771 | sum += num;
772 | }
773 |
774 | sum === 15;
775 |
776 | // good
777 | let sum = 0;
778 | numbers.forEach((num) => sum += num);
779 | sum === 15;
780 |
781 | // best (use the functional force)
782 | const sum = numbers.reduce((total, num) => total + num, 0);
783 | sum === 15;
784 | ```
785 |
786 | - [11.2](#11.2) Don't use generators for now.
787 |
788 | > Why? They don't transpile well to ES5.
789 |
790 | **[⬆ back to top](#table-of-contents)**
791 |
792 |
793 | ## Properties
794 |
795 | - [12.1](#12.1) Use dot notation when accessing properties.
796 |
797 | ```javascript
798 | const luke = {
799 | jedi: true,
800 | age: 28,
801 | };
802 |
803 | // bad
804 | const isJedi = luke['jedi'];
805 |
806 | // good
807 | const isJedi = luke.jedi;
808 | ```
809 |
810 | - [12.2](#12.2) Use subscript notation `[]` when accessing properties with a variable.
811 |
812 | ```javascript
813 | const luke = {
814 | jedi: true,
815 | age: 28,
816 | };
817 |
818 | function getProp(prop) {
819 | return luke[prop];
820 | }
821 |
822 | const isJedi = getProp('jedi');
823 | ```
824 |
825 | **[⬆ back to top](#table-of-contents)**
826 |
827 |
828 | ## Variables
829 |
830 | - [13.1](#13.1) Always use `const` 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.
831 |
832 | ```javascript
833 | // bad
834 | superPower = new SuperPower();
835 |
836 | // good
837 | const superPower = new SuperPower();
838 | ```
839 |
840 | - [13.2](#13.2) Use one `const` declaration per variable.
841 |
842 | > Why? It's easier to add new variable declarations this way, and you never have to worry about swapping out a `;` for a `,` or introducing punctuation-only diffs.
843 |
844 | ```javascript
845 | // bad
846 | const items = getItems(),
847 | goSportsTeam = true,
848 | dragonball = 'z';
849 |
850 | // bad
851 | // (compare to above, and try to spot the mistake)
852 | const items = getItems(),
853 | goSportsTeam = true;
854 | dragonball = 'z';
855 |
856 | // good
857 | const items = getItems();
858 | const goSportsTeam = true;
859 | const dragonball = 'z';
860 | ```
861 |
862 | - [13.3](#13.3) Group all your `const`s and then group all your `let`s.
863 |
864 | > Why? This is helpful when later on you might need to assign a variable depending on one of the previous assigned variables.
865 |
866 | ```javascript
867 | // bad
868 | let i, len, dragonball,
869 | items = getItems(),
870 | goSportsTeam = true;
871 |
872 | // bad
873 | let i;
874 | const items = getItems();
875 | let dragonball;
876 | const goSportsTeam = true;
877 | let len;
878 |
879 | // good
880 | const goSportsTeam = true;
881 | const items = getItems();
882 | let dragonball;
883 | let i;
884 | let length;
885 | ```
886 |
887 | - [13.4](#13.4) Assign variables where you need them, but place them in a reasonable place.
888 |
889 | > Why? `let` and `const` are block scoped and not function scoped.
890 |
891 | ```javascript
892 | // good
893 | function() {
894 | test();
895 | console.log('doing stuff..');
896 |
897 | //..other stuff..
898 |
899 | const name = getName();
900 |
901 | if (name === 'test') {
902 | return false;
903 | }
904 |
905 | return name;
906 | }
907 |
908 | // bad - unnessary function call
909 | function(hasName) {
910 | const name = getName();
911 |
912 | if (!hasName) {
913 | return false;
914 | }
915 |
916 | this.setFirstName(name);
917 |
918 | return true;
919 | }
920 |
921 | // good
922 | function(hasName) {
923 | if (!hasName) {
924 | return false;
925 | }
926 |
927 | const name = getName();
928 | this.setFirstName(name);
929 |
930 | return true;
931 | }
932 | ```
933 |
934 | **[⬆ back to top](#table-of-contents)**
935 |
936 |
937 | ## Hoisting
938 |
939 | - [14.1](#14.1) [14.2](#14.2) [14.3](#14.3) [14.4](#14.4) Non-rules removed in the Meteor edition.
940 |
941 |
942 | - For more information refer to [JavaScript Scoping & Hoisting](http://www.adequatelygood.com/2010/2/JavaS cript-Scoping-and-Hoisting) by [Ben Cherry](http://www.adequatelygood.com/).
943 |
944 | **[⬆ back to top](#table-of-contents)**
945 |
946 |
947 | ## Comparison Operators & Equality
948 |
949 | - [15.1](#15.1) Use `===` and `!==` over `==` and `!=`.
950 | - [15.2](#15.2)/[15.3](#15.3)/[15.4](#15.4)
951 | Use shortcuts. Note: Conditional statements such as the `if` statement evaluate their expression using coercion with the `ToBoolean` abstract method and always follow the simple rules below. For more information see [Truth Equality and JavaScript](http://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108) by Angus Croll. (15.2, 15.3, and 15.4 merged in Meteor edition):
952 |
953 | + **Objects** evaluate to **true**
954 | + **Undefined** evaluates to **false**
955 | + **Null** evaluates to **false**
956 | + **Booleans** evaluate to **the value of the boolean**
957 | + **Numbers** evaluate to **false** if **+0, -0, or NaN**, otherwise **true**
958 | + **Strings** evaluate to **false** if an empty string `''`, otherwise **true**
959 |
960 | ```javascript
961 | // bad
962 | if (name !== '') {
963 | // ...stuff...
964 | }
965 |
966 | // good
967 | if (name) {
968 | // ...stuff...
969 | }
970 |
971 | // bad
972 | if (collection.length > 0) {
973 | // ...stuff...
974 | }
975 |
976 | // good
977 | if (collection.length) {
978 | // ...stuff...
979 | }
980 |
981 | // note
982 | if ([0]) {
983 | // true
984 | // An array is an object, objects evaluate to true
985 | }
986 | ```
987 |
988 | **[⬆ back to top](#table-of-contents)**
989 |
990 |
991 | ## Blocks
992 |
993 | - [16.1](#16.1)
994 | Use braces with all multi-line blocks.
995 |
996 | ```javascript
997 | // bad
998 | if (test)
999 | return false;
1000 |
1001 | // good
1002 | if (test) return false;
1003 |
1004 | // good
1005 | if (test) {
1006 | return false;
1007 | }
1008 |
1009 | // bad
1010 | function() { return false; }
1011 |
1012 | // good
1013 | function() {
1014 | return false;
1015 | }
1016 | ```
1017 |
1018 | - [16.2](#16.2)
1019 | If you're using multi-line blocks with `if` and `else`, put `else` on the same line as your
1020 | `if` block's closing brace.
1021 |
1022 | ```javascript
1023 | // bad
1024 | if (test) {
1025 | thing1();
1026 | thing2();
1027 | }
1028 | else {
1029 | thing3();
1030 | }
1031 |
1032 | // good
1033 | if (test) {
1034 | thing1();
1035 | thing2();
1036 | } else {
1037 | thing3();
1038 | }
1039 | ```
1040 |
1041 |
1042 | **[⬆ back to top](#table-of-contents)**
1043 |
1044 |
1045 | ## Comments
1046 |
1047 | - [17.1](#17.1) Use `/** ... */` for method doc comments. Include a description, specify types and values for all parameters and return values. In the Meteor edition, this rule has been updated to only refer to doc comments.
1048 |
1049 | ```javascript
1050 | // bad
1051 | // make() returns a new element
1052 | // based on the passed in tag name
1053 | //
1054 | // @param {String} tag
1055 | // @return {Element} element
1056 | function make(tag) {
1057 |
1058 | // ...stuff...
1059 |
1060 | return element;
1061 | }
1062 |
1063 | // good
1064 | /**
1065 | * make() returns a new element
1066 | * based on the passed in tag name
1067 | *
1068 | * @param {String} tag
1069 | * @return {Element} element
1070 | */
1071 | function make(tag) {
1072 |
1073 | // ...stuff...
1074 |
1075 | return element;
1076 | }
1077 | ```
1078 |
1079 | - [17.2](#17.2) Use `//` for all other comments. Place single line comments on a newline above the subject of the comment. Put an empty line before the comment. Has been updated in Meteor edition to refer to all non-doc comments.
1080 |
1081 | ```javascript
1082 | // bad
1083 | const active = true; // is current tab
1084 |
1085 | // good
1086 | // is current tab
1087 | const active = true;
1088 |
1089 | // bad
1090 | function getType() {
1091 | console.log('fetching type...');
1092 | // set the default type to 'no type'
1093 | const type = this._type || 'no type';
1094 |
1095 | return type;
1096 | }
1097 |
1098 | // good
1099 | function getType() {
1100 | console.log('fetching type...');
1101 |
1102 | // set the default type to 'no type'
1103 | const type = this._type || 'no type';
1104 |
1105 | return type;
1106 | }
1107 | ```
1108 |
1109 | - [17.3](#17.3) 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`.
1110 |
1111 | - [17.4](#17.4) Use `// FIXME:` to annotate problems.
1112 |
1113 | ```javascript
1114 | class Calculator {
1115 | constructor() {
1116 | // FIXME: shouldn't use a global here
1117 | total = 0;
1118 | }
1119 | }
1120 | ```
1121 |
1122 | - [17.5](#17.5) Use `// TODO:` to annotate solutions to problems.
1123 |
1124 | ```javascript
1125 | class Calculator {
1126 | constructor() {
1127 | // TODO: total should be configurable by an options param
1128 | this.total = 0;
1129 | }
1130 | }
1131 | ```
1132 |
1133 | **[⬆ back to top](#table-of-contents)**
1134 |
1135 |
1136 | ## Whitespace
1137 |
1138 | - [18.1](#18.1)
1139 | Use soft tabs set to 2 spaces.
1140 |
1141 | ```javascript
1142 | // bad
1143 | function() {
1144 | ∙∙∙∙const name;
1145 | }
1146 |
1147 | // bad
1148 | function() {
1149 | ∙const name;
1150 | }
1151 |
1152 | // good
1153 | function() {
1154 | ∙∙const name;
1155 | }
1156 | ```
1157 |
1158 | - [18.2](#18.2)
1159 | Place 1 space before the leading brace.
1160 |
1161 | ```javascript
1162 | // bad
1163 | function test(){
1164 | console.log('test');
1165 | }
1166 |
1167 | // good
1168 | function test() {
1169 | console.log('test');
1170 | }
1171 |
1172 | // bad
1173 | dog.set('attr',{
1174 | age: '1 year',
1175 | breed: 'Bernese Mountain Dog',
1176 | });
1177 |
1178 | // good
1179 | dog.set('attr', {
1180 | age: '1 year',
1181 | breed: 'Bernese Mountain Dog',
1182 | });
1183 | ```
1184 |
1185 | - [18.3](#18.3)
1186 | Place 1 space before the opening parenthesis in control statements (`if`, `while` etc.). Place no space before the argument list in function calls and declarations.
1187 |
1188 | ```javascript
1189 | // bad
1190 | if(isJedi) {
1191 | fight ();
1192 | }
1193 |
1194 | // good
1195 | if (isJedi) {
1196 | fight();
1197 | }
1198 |
1199 | // bad
1200 | function fight () {
1201 | console.log ('Swooosh!');
1202 | }
1203 |
1204 | // good
1205 | function fight() {
1206 | console.log('Swooosh!');
1207 | }
1208 | ```
1209 |
1210 | - [18.4](#18.4)
1211 | Set off operators with spaces.
1212 |
1213 | ```javascript
1214 | // bad
1215 | const x=y+5;
1216 |
1217 | // good
1218 | const x = y + 5;
1219 | ```
1220 |
1221 | - [18.5](#18.5) End files with a single newline character.
1222 |
1223 | ```javascript
1224 | // bad
1225 | (function(global) {
1226 | // ...stuff...
1227 | })(this);
1228 | ```
1229 |
1230 | ```javascript
1231 | // bad
1232 | (function(global) {
1233 | // ...stuff...
1234 | })(this);↵
1235 | ↵
1236 | ```
1237 |
1238 | ```javascript
1239 | // good
1240 | (function(global) {
1241 | // ...stuff...
1242 | })(this);↵
1243 | ```
1244 |
1245 | - [18.5](#18.5) Use indentation when making long method chains. Use a leading dot, which
1246 | emphasizes that the line is a method call, not a new statement.
1247 |
1248 | ```javascript
1249 | // bad
1250 | $('#items').find('.selected').highlight().end().find('.open').updateCount();
1251 |
1252 | // bad
1253 | $('#items').
1254 | find('.selected').
1255 | highlight().
1256 | end().
1257 | find('.open').
1258 | updateCount();
1259 |
1260 | // good
1261 | $('#items')
1262 | .find('.selected')
1263 | .highlight()
1264 | .end()
1265 | .find('.open')
1266 | .updateCount();
1267 |
1268 | // bad
1269 | const leds = stage.selectAll('.led').data(data).enter().append('svg:svg').class('led', true)
1270 | .attr('width', (radius + margin) * 2).append('svg:g')
1271 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
1272 | .call(tron.led);
1273 |
1274 | // good
1275 | const leds = stage.selectAll('.led')
1276 | .data(data)
1277 | .enter().append('svg:svg')
1278 | .classed('led', true)
1279 | .attr('width', (radius + margin) * 2)
1280 | .append('svg:g')
1281 | .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
1282 | .call(tron.led);
1283 | ```
1284 |
1285 | - [18.6](#18.6) Leave a blank line after blocks and before the next statement.
1286 |
1287 | ```javascript
1288 | // bad
1289 | if (foo) {
1290 | return bar;
1291 | }
1292 | return baz;
1293 |
1294 | // good
1295 | if (foo) {
1296 | return bar;
1297 | }
1298 |
1299 | return baz;
1300 |
1301 | // bad
1302 | const obj = {
1303 | foo() {
1304 | },
1305 | bar() {
1306 | },
1307 | };
1308 | return obj;
1309 |
1310 | // good
1311 | const obj = {
1312 | foo() {
1313 | },
1314 |
1315 | bar() {
1316 | },
1317 | };
1318 |
1319 | return obj;
1320 | ```
1321 |
1322 |
1323 | **[⬆ back to top](#table-of-contents)**
1324 |
1325 | ## Commas
1326 |
1327 | - [19.1](#19.1)
1328 | Leading commas: **Nope.**
1329 |
1330 | ```javascript
1331 | // bad
1332 | const story = [
1333 | once
1334 | , upon
1335 | , aTime
1336 | ];
1337 |
1338 | // good
1339 | const story = [
1340 | once,
1341 | upon,
1342 | aTime,
1343 | ];
1344 |
1345 | // bad
1346 | const hero = {
1347 | firstName: 'Ada'
1348 | , lastName: 'Lovelace'
1349 | , birthYear: 1815
1350 | , superPower: 'computers'
1351 | };
1352 |
1353 | // good
1354 | const hero = {
1355 | firstName: 'Ada',
1356 | lastName: 'Lovelace',
1357 | birthYear: 1815,
1358 | superPower: 'computers',
1359 | };
1360 | ```
1361 |
1362 | - [19.2](#19.2)
1363 | Additional trailing comma: **Yup.**
1364 |
1365 | > Why? This leads to cleaner git diffs. Also, transpilers like Babel will remove the additional trailing comma in the transpiled code which means you don't have to worry about the [trailing comma problem](es5/README.md#commas) in legacy browsers.
1366 |
1367 | ```javascript
1368 | // bad - git diff without trailing comma
1369 | const hero = {
1370 | firstName: 'Florence',
1371 | - lastName: 'Nightingale'
1372 | + lastName: 'Nightingale',
1373 | + inventorOf: ['coxcomb graph', 'mordern nursing']
1374 | }
1375 |
1376 | // good - git diff with trailing comma
1377 | const hero = {
1378 | firstName: 'Florence',
1379 | lastName: 'Nightingale',
1380 | + inventorOf: ['coxcomb chart', 'mordern nursing'],
1381 | }
1382 |
1383 | // bad
1384 | const hero = {
1385 | firstName: 'Dana',
1386 | lastName: 'Scully'
1387 | };
1388 |
1389 | const heroes = [
1390 | 'Batman',
1391 | 'Superman'
1392 | ];
1393 |
1394 | // good
1395 | const hero = {
1396 | firstName: 'Dana',
1397 | lastName: 'Scully',
1398 | };
1399 |
1400 | const heroes = [
1401 | 'Batman',
1402 | 'Superman',
1403 | ];
1404 | ```
1405 |
1406 | **[⬆ back to top](#table-of-contents)**
1407 |
1408 |
1409 | ## Semicolons
1410 |
1411 | - [20.1](#20.1)
1412 | **Yup.**
1413 |
1414 | ```javascript
1415 | // bad
1416 | (function() {
1417 | const name = 'Skywalker'
1418 | return name
1419 | })()
1420 |
1421 | // good
1422 | (() => {
1423 | const name = 'Skywalker';
1424 | return name;
1425 | })();
1426 |
1427 | // good (guards against the function becoming an argument when two files with IIFEs are concatenated)
1428 | ;(() => {
1429 | const name = 'Skywalker';
1430 | return name;
1431 | })();
1432 | ```
1433 |
1434 | [Read more](http://stackoverflow.com/a/7365214/1712802).
1435 |
1436 | **[⬆ back to top](#table-of-contents)**
1437 |
1438 |
1439 | ## Type Casting & Coercion
1440 |
1441 | - [21.1](#21.1) Perform type coercion at the beginning of the statement.
1442 | - [21.2](#21.2) Strings:
1443 |
1444 | ```javascript
1445 | // => this.reviewScore = 9;
1446 |
1447 | // bad
1448 | const totalScore = this.reviewScore + '';
1449 |
1450 | // good
1451 | const totalScore = String(this.reviewScore);
1452 | ```
1453 |
1454 | - [21.3](#21.3)
1455 | Use `parseInt` to convert strings to numbers, and always with a radix argument.
1456 |
1457 | ```javascript
1458 | const inputValue = '4';
1459 |
1460 | // bad
1461 | const val = new Number(inputValue);
1462 |
1463 | // bad
1464 | const val = inputValue >> 0;
1465 |
1466 | // bad
1467 | const val = parseInt(inputValue);
1468 |
1469 | // good
1470 | const val = parseInt(inputValue, 10);
1471 | ```
1472 |
1473 | Use the `Number` constructor (without `new`) to coerce values that are
1474 | not strings to numbers, as in `Number(new Date) + 1000`. The unary `+`
1475 | operator is an acceptable shorthand for `Number(...)`, but only if the
1476 | expression is not involved in a larger expression, as in `+new Date`.
1477 |
1478 | Note that the `Number` constructor will return `NaN` if the value
1479 | cannot be converted to a number, including when the value is
1480 | undefined. If the output might be `NaN` (likely because the input
1481 | might be undefined), be sure to test for that possibility after
1482 | attempting the conversion:
1483 |
1484 | ```javascript
1485 | let val = Number(inputValue);
1486 | if (isNaN(val)) {
1487 | val = 0;
1488 | }
1489 | ```
1490 |
1491 | Better yet, avoid the possibility of `NaN` through other means, such
1492 | as providing default values for optional function parameters.
1493 |
1494 | - [21.4](#21.4) If you have a very good reason for
1495 | using some other kind of coercion technique, be it for performance or
1496 | because you need a very specific output behavior, then you should
1497 | absolutely leave a comment justifying your choice.
1498 |
1499 | ```javascript
1500 | // good
1501 | /**
1502 | * parseInt was the reason my code was slow.
1503 | * Bitshifting the String to coerce it to a
1504 | * Number made it a lot faster.
1505 | */
1506 | const val = inputValue >> 0;
1507 |
1508 | // good
1509 | // Truthy inputs must always be coerced to 1, and falsy inputs must
1510 | // always be cocerced to 0.
1511 | const zeroOrOne = inputValue ? 1 : 0;
1512 | ```
1513 |
1514 | - [21.5](#21.5) **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). Largest signed 32-bit Int is 2,147,483,647:
1515 |
1516 | ```javascript
1517 | 2147483647 >> 0 //=> 2147483647
1518 | 2147483648 >> 0 //=> -2147483648
1519 | 2147483649 >> 0 //=> -2147483647
1520 | ```
1521 |
1522 | - [21.6](#21.6) Booleans:
1523 |
1524 | ```javascript
1525 | const age = 0;
1526 |
1527 | // bad
1528 | const hasAge = new Boolean(age);
1529 |
1530 | // good
1531 | const hasAge = Boolean(age);
1532 |
1533 | // good
1534 | const hasAge = !!age;
1535 | ```
1536 |
1537 | **[⬆ back to top](#table-of-contents)**
1538 |
1539 |
1540 | ## Naming Conventions
1541 |
1542 | - [22.1](#22.1) Avoid single letter names. Be descriptive with your naming.
1543 |
1544 | ```javascript
1545 | // bad
1546 | function q() {
1547 | // ...stuff...
1548 | }
1549 |
1550 | // good
1551 | function query() {
1552 | // ..stuff..
1553 | }
1554 | ```
1555 |
1556 | - [22.2](#22.2)
1557 | Use camelCase when naming objects, functions, and instances.
1558 |
1559 | ```javascript
1560 | // bad
1561 | const OBJEcttsssss = {};
1562 | const this_is_my_object = {};
1563 | function c() {}
1564 |
1565 | // good
1566 | const thisIsMyObject = {};
1567 | function thisIsMyFunction() {}
1568 | ```
1569 |
1570 | - [22.3](#22.3) Use PascalCase when naming constructors or classes.
1571 |
1572 | ```javascript
1573 | // bad
1574 | function user(options) {
1575 | this.name = options.name;
1576 | }
1577 |
1578 | const bad = new user({
1579 | name: 'nope',
1580 | });
1581 |
1582 | // good
1583 | class User {
1584 | constructor(options) {
1585 | this.name = options.name;
1586 | }
1587 | }
1588 |
1589 | const good = new User({
1590 | name: 'yup',
1591 | });
1592 | ```
1593 |
1594 | - [22.4](#22.4) Use a leading underscore `_` when naming private properties.
1595 |
1596 | ```javascript
1597 | // bad
1598 | this.__firstName__ = 'Panda';
1599 | this.firstName_ = 'Panda';
1600 |
1601 | // good
1602 | this._firstName = 'Panda';
1603 | ```
1604 |
1605 | - [22.5](#22.5) Don't save references to `this`. Use arrow functions or Function#bind.
1606 |
1607 | ```javascript
1608 | // bad
1609 | function foo() {
1610 | const self = this;
1611 | return function() {
1612 | console.log(self);
1613 | };
1614 | }
1615 |
1616 | // bad
1617 | function foo() {
1618 | const that = this;
1619 | return function() {
1620 | console.log(that);
1621 | };
1622 | }
1623 |
1624 | // good
1625 | function foo() {
1626 | return () => {
1627 | console.log(this);
1628 | };
1629 | }
1630 | ```
1631 |
1632 | - [22.6](#22.6) If your file exports a single class, your filename should be exactly the name of the class.
1633 | ```javascript
1634 | // file contents
1635 | export default class CheckBox {
1636 | // ...
1637 | }
1638 |
1639 | // in some other file
1640 | // bad
1641 | import CheckBox from './checkBox';
1642 |
1643 | // bad
1644 | import CheckBox from './check_box';
1645 |
1646 | // good
1647 | import CheckBox from './CheckBox';
1648 | ```
1649 |
1650 | - [22.7](#22.7) Use camelCase when you export-default a function. Your filename should be identical to your function's name.
1651 |
1652 | ```javascript
1653 | function makeStyleGuide() {
1654 | }
1655 |
1656 | export default makeStyleGuide;
1657 | ```
1658 |
1659 | - [22.8](#22.8) Use PascalCase when you export a singleton / function library / bare object.
1660 |
1661 | ```javascript
1662 | const AirbnbStyleGuide = {
1663 | es6: {
1664 | }
1665 | };
1666 |
1667 | export default AirbnbStyleGuide;
1668 | ```
1669 |
1670 | - [22.9](#22.9) Prefer `export`ing declarations
1671 | where they are declared, rather than at the end of the file:
1672 |
1673 | ```javascript
1674 | // bad
1675 | function createUser(name) { ... }
1676 | function getOrCreateUser(name) { ... }
1677 | // ... rest of file ...
1678 | export {
1679 | createUser,
1680 | getOrCreateUser,
1681 | }
1682 |
1683 | // good
1684 | export function createUser(name) { ... }
1685 | export function getOrCreateUser(name) { ... }
1686 | // ... rest of file ...
1687 | ```
1688 |
1689 | This style ensures that the set of `export`s remains up-to-date as
1690 | declarations are added or removed.
1691 |
1692 | **[⬆ back to top](#table-of-contents)**
1693 |
1694 |
1695 | ## Accessors
1696 |
1697 | - [23.1](#23.1) Accessor functions for properties are not required.
1698 | - [23.2](#23.2) If you do make accessor functions use getVal() and setVal('hello').
1699 |
1700 | ```javascript
1701 | // bad
1702 | dragon.age();
1703 |
1704 | // good
1705 | dragon.getAge();
1706 |
1707 | // bad
1708 | dragon.age(25);
1709 |
1710 | // good
1711 | dragon.setAge(25);
1712 | ```
1713 |
1714 | - [23.3](#23.3) If the property is a boolean, use isVal() or hasVal().
1715 |
1716 | ```javascript
1717 | // bad
1718 | if (!dragon.age()) {
1719 | return false;
1720 | }
1721 |
1722 | // good
1723 | if (!dragon.hasAge()) {
1724 | return false;
1725 | }
1726 | ```
1727 |
1728 | - [23.4](#23.4) It's okay to create get() and set() functions, but be consistent.
1729 |
1730 | ```javascript
1731 | class Jedi {
1732 | constructor(options = {}) {
1733 | const lightsaber = options.lightsaber || 'blue';
1734 | this.set('lightsaber', lightsaber);
1735 | }
1736 |
1737 | set(key, val) {
1738 | this[key] = val;
1739 | }
1740 |
1741 | get(key) {
1742 | return this[key];
1743 | }
1744 | }
1745 | ```
1746 |
1747 | - [23.5](#23.5) Strongly prefer accessor methods to
1748 | defining ES5 getter and setter properties:
1749 |
1750 | ```javascript
1751 | class Jedi {
1752 | constructor({ lightsaber = blue }) {
1753 | this._lightsaber = lightsaber;
1754 | }
1755 |
1756 | // bad; use a normal getter method instead
1757 | get lightsaber() {
1758 | return this._lightsaber;
1759 | }
1760 |
1761 | // bad; use a normal setter method instead
1762 | set lightsaber(newLightSaber) {
1763 | return this._lightsaber = newLightSaber;
1764 | }
1765 | }
1766 | ```
1767 |
1768 | Not only is this style rarely more readable than the method
1769 | equivalent, performance can suffer dramatically when code relies on
1770 | specially-defined properties rather than just using normal properties.
1771 |
1772 | **[⬆ back to top](#table-of-contents)**
1773 |
1774 |
1775 | ## Events
1776 |
1777 | - [24.1](#24.1) 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:
1778 |
1779 | ```javascript
1780 | // bad
1781 | $(this).trigger('listingUpdated', listing.id);
1782 |
1783 | ...
1784 |
1785 | $(this).on('listingUpdated', function(e, listingId) {
1786 | // do something with listingId
1787 | });
1788 | ```
1789 |
1790 | prefer:
1791 |
1792 | ```javascript
1793 | // good
1794 | $(this).trigger('listingUpdated', { listingId : listing.id });
1795 |
1796 | ...
1797 |
1798 | $(this).on('listingUpdated', function(e, data) {
1799 | // do something with data.listingId
1800 | });
1801 | ```
1802 |
1803 | **[⬆ back to top](#table-of-contents)**
1804 |
1805 |
1806 | ## jQuery
1807 |
1808 | - [25.1](#25.1) Prefix jQuery object variables with a `$`.
1809 |
1810 | ```javascript
1811 | // bad
1812 | const sidebar = $('.sidebar');
1813 |
1814 | // good
1815 | const $sidebar = $('.sidebar');
1816 | ```
1817 |
1818 | - [25.2](#25.2) Cache jQuery lookups.
1819 |
1820 | ```javascript
1821 | // bad
1822 | function setSidebar() {
1823 | $('.sidebar').hide();
1824 |
1825 | // ...stuff...
1826 |
1827 | $('.sidebar').css({
1828 | 'background-color': 'pink'
1829 | });
1830 | }
1831 |
1832 | // good
1833 | function setSidebar() {
1834 | const $sidebar = $('.sidebar');
1835 | $sidebar.hide();
1836 |
1837 | // ...stuff...
1838 |
1839 | $sidebar.css({
1840 | 'background-color': 'pink'
1841 | });
1842 | }
1843 | ```
1844 |
1845 | - [25.3](#25.3) For DOM queries use Cascading `$('.sidebar ul')` or parent > child `$('.sidebar > ul')`. [jsPerf](http://jsperf.com/jquery-find-vs-context-sel/16)
1846 | - [25.4](#25.4) Use `find` with scoped jQuery object queries.
1847 |
1848 | ```javascript
1849 | // bad
1850 | $('ul', '.sidebar').hide();
1851 |
1852 | // bad
1853 | $('.sidebar').find('ul').hide();
1854 |
1855 | // good
1856 | $('.sidebar ul').hide();
1857 |
1858 | // good
1859 | $('.sidebar > ul').hide();
1860 |
1861 | // good
1862 | $sidebar.find('ul').hide();
1863 | ```
1864 |
1865 | **[⬆ back to top](#table-of-contents)**
1866 |
1867 |
1868 | ## ECMAScript 5 Compatibility
1869 |
1870 | - [26.1](#26.1) Refer to [Kangax](https://twitter.com/kangax/)'s ES5 [compatibility table](http://kangax.github.com/es5-compat-table/).
1871 |
1872 | **[⬆ back to top](#table-of-contents)**
1873 |
1874 | ## ECMAScript 6 Styles
1875 |
1876 | - [27.1](#27.1) This is a collection of links to the various es6 features.
1877 |
1878 | 1. [Arrow Functions](#arrow-functions)
1879 | 1. [Classes](#constructors)
1880 | 1. [Object Shorthand](#es6-object-shorthand)
1881 | 1. [Object Concise](#es6-object-concise)
1882 | 1. [Object Computed Properties](#es6-computed-properties)
1883 | 1. [Template Strings](#es6-template-literals)
1884 | 1. [Destructuring](#destructuring)
1885 | 1. [Default Parameters](#es6-default-parameters)
1886 | 1. [Rest](#es6-rest)
1887 | 1. [Array Spreads](#es6-array-spreads)
1888 | 1. [Let and Const](#references)
1889 | 1. [Iterators and Generators](#iterators-and-generators)
1890 | 1. [Modules](#modules)
1891 |
1892 | **[⬆ back to top](#table-of-contents)**
1893 |
1894 |
1895 | ## Contributors
1896 |
1897 | - [View Contributors](https://github.com/airbnb/javascript/graphs/contributors)
1898 |
1899 |
1900 | ## License
1901 |
1902 | (The MIT License)
1903 |
1904 | Copyright (c) 2014 Airbnb
1905 |
1906 | Permission is hereby granted, free of charge, to any person obtaining
1907 | a copy of this software and associated documentation files (the
1908 | 'Software'), to deal in the Software without restriction, including
1909 | without limitation the rights to use, copy, modify, merge, publish,
1910 | distribute, sublicense, and/or sell copies of the Software, and to
1911 | permit persons to whom the Software is furnished to do so, subject to
1912 | the following conditions:
1913 |
1914 | The above copyright notice and this permission notice shall be
1915 | included in all copies or substantial portions of the Software.
1916 |
1917 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
1918 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1919 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1920 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1921 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1922 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1923 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1924 |
1925 | **[⬆ back to top](#table-of-contents)**
1926 |
1927 | # };
1928 |
--------------------------------------------------------------------------------
/es5/README.md:
--------------------------------------------------------------------------------
1 | [](https://gitter.im/airbnb/javascript?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
2 |
3 | # Airbnb JavaScript Style Guide() {
4 |
5 | *A mostly reasonable approach to JavaScript*
6 |
7 |
8 | ## Table of Contents
9 |
10 | 1. [Types](#types)
11 | 1. [Objects](#objects)
12 | 1. [Arrays](#arrays)
13 | 1. [Strings](#strings)
14 | 1. [Functions](#functions)
15 | 1. [Properties](#properties)
16 | 1. [Variables](#variables)
17 | 1. [Hoisting](#hoisting)
18 | 1. [Comparison Operators & Equality](#comparison-operators--equality)
19 | 1. [Blocks](#blocks)
20 | 1. [Comments](#comments)
21 | 1. [Whitespace](#whitespace)
22 | 1. [Commas](#commas)
23 | 1. [Semicolons](#semicolons)
24 | 1. [Type Casting & Coercion](#type-casting--coercion)
25 | 1. [Naming Conventions](#naming-conventions)
26 | 1. [Accessors](#accessors)
27 | 1. [Constructors](#constructors)
28 | 1. [Events](#events)
29 | 1. [Modules](#modules)
30 | 1. [jQuery](#jquery)
31 | 1. [ECMAScript 5 Compatibility](#ecmascript-5-compatibility)
32 | 1. [Testing](#testing)
33 | 1. [Performance](#performance)
34 | 1. [Resources](#resources)
35 | 1. [In the Wild](#in-the-wild)
36 | 1. [Translation](#translation)
37 | 1. [The JavaScript Style Guide Guide](#the-javascript-style-guide-guide)
38 | 1. [Chat With Us About Javascript](#chat-with-us-about-javascript)
39 | 1. [Contributors](#contributors)
40 | 1. [License](#license)
41 |
42 | ## Types
43 |
44 | - **Primitives**: When you access a primitive type you work directly on its value.
45 |
46 | + `string`
47 | + `number`
48 | + `boolean`
49 | + `null`
50 | + `undefined`
51 |
52 | ```javascript
53 | var foo = 1;
54 | var bar = foo;
55 |
56 | bar = 9;
57 |
58 | console.log(foo, bar); // => 1, 9
59 | ```
60 | - **Complex**: When you access a complex type you work on a reference to its value.
61 |
62 | + `object`
63 | + `array`
64 | + `function`
65 |
66 | ```javascript
67 | var foo = [1, 2];
68 | var bar = foo;
69 |
70 | bar[0] = 9;
71 |
72 | console.log(foo[0], bar[0]); // => 9, 9
73 | ```
74 |
75 | **[⬆ back to top](#table-of-contents)**
76 |
77 | ## Objects
78 |
79 | - Use the literal syntax for object creation.
80 |
81 | ```javascript
82 | // bad
83 | var item = new Object();
84 |
85 | // good
86 | var item = {};
87 | ```
88 |
89 | - 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).
90 |
91 | ```javascript
92 | // bad
93 | var superman = {
94 | default: { clark: 'kent' },
95 | private: true
96 | };
97 |
98 | // good
99 | var superman = {
100 | defaults: { clark: 'kent' },
101 | hidden: true
102 | };
103 | ```
104 |
105 | - Use readable synonyms in place of reserved words.
106 |
107 | ```javascript
108 | // bad
109 | var superman = {
110 | class: 'alien'
111 | };
112 |
113 | // bad
114 | var superman = {
115 | klass: 'alien'
116 | };
117 |
118 | // good
119 | var superman = {
120 | type: 'alien'
121 | };
122 | ```
123 |
124 | **[⬆ back to top](#table-of-contents)**
125 |
126 | ## Arrays
127 |
128 | - Use the literal syntax for array creation.
129 |
130 | ```javascript
131 | // bad
132 | var items = new Array();
133 |
134 | // good
135 | var items = [];
136 | ```
137 |
138 | - Use Array#push instead of direct assignment to add items to an array.
139 |
140 | ```javascript
141 | var someStack = [];
142 |
143 |
144 | // bad
145 | someStack[someStack.length] = 'abracadabra';
146 |
147 | // good
148 | someStack.push('abracadabra');
149 | ```
150 |
151 | - When you need to copy an array use Array#slice. [jsPerf](http://jsperf.com/converting-arguments-to-an-array/7)
152 |
153 | ```javascript
154 | var len = items.length;
155 | var itemsCopy = [];
156 | var i;
157 |
158 | // bad
159 | for (i = 0; i < len; i++) {
160 | itemsCopy[i] = items[i];
161 | }
162 |
163 | // good
164 | itemsCopy = items.slice();
165 | ```
166 |
167 | - To convert an array-like object to an array, use Array#slice.
168 |
169 | ```javascript
170 | function trigger() {
171 | var args = Array.prototype.slice.call(arguments);
172 | ...
173 | }
174 | ```
175 |
176 | **[⬆ back to top](#table-of-contents)**
177 |
178 |
179 | ## Strings
180 |
181 | - Use single quotes `''` for strings.
182 |
183 | ```javascript
184 | // bad
185 | var name = "Bob Parr";
186 |
187 | // good
188 | var name = 'Bob Parr';
189 |
190 | // bad
191 | var fullName = "Bob " + this.lastName;
192 |
193 | // good
194 | var fullName = 'Bob ' + this.lastName;
195 | ```
196 |
197 | - Strings longer than 80 characters should be written across multiple lines using string concatenation.
198 | - 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).
199 |
200 | ```javascript
201 | // bad
202 | var 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.';
203 |
204 | // bad
205 | var errorMessage = 'This is a super long error that was thrown because \
206 | of Batman. When you stop to think about how Batman had anything to do \
207 | with this, you would get nowhere \
208 | fast.';
209 |
210 | // good
211 | var errorMessage = 'This is a super long error that was thrown because ' +
212 | 'of Batman. When you stop to think about how Batman had anything to do ' +
213 | 'with this, you would get nowhere fast.';
214 | ```
215 |
216 | - 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).
217 |
218 | ```javascript
219 | var items;
220 | var messages;
221 | var length;
222 | var i;
223 |
224 | messages = [{
225 | state: 'success',
226 | message: 'This one worked.'
227 | }, {
228 | state: 'success',
229 | message: 'This one worked as well.'
230 | }, {
231 | state: 'error',
232 | message: 'This one did not work.'
233 | }];
234 |
235 | length = messages.length;
236 |
237 | // bad
238 | function inbox(messages) {
239 | items = '