└── README.md
/README.md:
--------------------------------------------------------------------------------
1 | ## [Yandex Style Guide](https://github.com/yandex/codestyle/blob/master/javascript.ru.md)
2 |
3 | JavaScript CodeStyle
4 | ====================
5 | - [Общие положения](#1)
6 | - [Именование](#2)
7 | - [Объявление переменных](#3)
8 | - [Литералы](#4)
9 | - [Объекты](#4-1)
10 | - [Массивы](#4-2)
11 | - [Строки](#4-3)
12 | - [Точка с запятой](#5)
13 | - [Ключевые слова](#6)
14 | - [Блочные инструкции](#7)
15 | - [Условные инструкции](#8)
16 | - [if](#8-1)
17 | - [switch](#8-2)
18 | - [Циклы](#9)
19 | - [for](#9-1)
20 | - [for (var i in obj)](#9-2)
21 | - [Операторы](#10)
22 | - [with](#10-1)
23 | - [Оператор равенства](#10-2)
24 | - [Тернарный оператор](#10-3)
25 | - [Унарный оператор](#10-4)
26 | - [eval](#11)
27 | - [undefined](#12)
28 | - [Круглые скобки](#13)
29 | - [Исключения](#14)
30 | - [Приведение типов](#15)
31 | - [Переносы строк](#16)
32 | - [Цепочки вызовов](#17)
33 | - [Конкатенация строк](#18)
34 | - [Пустые линии](#19)
35 | - [Контекст функции](#20)
36 | - [Комментарии](#21)
37 | - [Классы](#22)
38 | - [node.js](#23)
39 | - [Импортирование модулей](#23-1)
40 |
41 | ##Именование
42 |
43 | * Кодировка UTF-8 без [BOM](http://en.wikipedia.org/wiki/Byte-order_mark).
44 | * Перевод строки: LF. В конце файла перевод строки **обязателен**.
45 | * Отступ 4 пробела, знаки табуляции не применяются.
46 | * Длина линии не должна превышать 120 символов.
47 | * Нет лишних пробелов в конце строк (настраиваем свой текстовый редактор, чтобы он удалял лишние пробелы при сохранении).
48 |
49 | ##Именование
50 | * `variableNamesLikeThis`
51 | * `functionNamesLikeThis`
52 | * `functionArgumentsLikeThis`
53 | * `ClassNamesLikeThis`
54 | * `methodNamesLikeThis`
55 | * `CONSTANTS_LIKE_THIS`
56 | * `namespaceLikeThis`
57 | * `event-like-this`
58 | * `private` свойства и методы объектов начинаются с подчеркивания `_`
59 | * `protected` свойства и методы объектов также начинаются с подчеркивания `_`
60 | * Избегаем коротких или немногословных названий
61 | * В именовании аббревиатур соблюдаем `CamelCase`. Например: `Json`, `Xml`.
62 |
63 | ##Объявление переменных
64 | * Все переменные объявляются с `var`.
65 | * Каждая переменная в пределах одной области видимости объявляется только один раз.
66 | * Каждая переменная объявляется на новой строке. Это позволяет легко менять строки местами и подписывать к ним комментарии.
67 | * Переменные объявляются как можно ближе к месту использования.
68 |
69 | **Хорошо:**
70 | ```javascript
71 | var keys = ['foo', 'bar'];
72 | var values = [23, 42];
73 |
74 | var object = {};
75 | while (items.length) {
76 | var key = keys.pop();
77 | object[key] = values.pop();
78 | }
79 | ```
80 |
81 | **Плохо:**
82 | ```javascript
83 | var keys = ['foo', 'bar'],
84 | values = [23, 42],
85 | object = {},
86 | key;
87 |
88 | while (items.length) {
89 | key = keys.pop();
90 | object[key] = values.pop();
91 | }
92 | ```
93 |
94 | ##Литералы
95 |
96 | ###Объекты
97 |
98 | * После открывающей фигурной скобки и перед закрывающей пробел не ставится:
99 |
100 | ```javascript
101 | var obj = {a: 1, b: 2, c: 3};
102 |
103 | this.method({a: 1, b: 2});
104 | ```
105 | * Пробел перед двоеточием не ставится:
106 |
107 | ```javascript
108 | var obj = {
109 | prop: 0
110 | };
111 | ```
112 | * Выравнивание не используется:
113 |
114 | **Хорошо:**
115 |
116 | ```javascript
117 | var obj = {
118 | a: 0,
119 | b: 1,
120 | lengthyName: 2
121 | };
122 | ```
123 | **Плохо:**
124 |
125 | ```javascript
126 | var obj = {
127 | a : 0,
128 | b : 1,
129 | lengthyName: 2
130 | };
131 | ```
132 | * Имена ключей заключаются в кавычки только по необходимости:
133 |
134 | **Хорошо:**
135 |
136 | ```javascript
137 | var obj = {
138 | key: 0,
139 | 'key-key': 1
140 | };
141 | ```
142 | **Плохо:**
143 | ```javascript
144 | var obj = {
145 | 'key': 0,
146 | 'key-key': 1
147 | };
148 | ```
149 |
150 | ###Массивы
151 |
152 | При объявлении массива, пробел ставится лишь после запятой:
153 |
154 | ```javascript
155 | var fellowship = ['foo', 'bar', 'baz'];
156 | ```
157 |
158 | ###Строки
159 | * Строки записываются с использованием одинарных кавычек:
160 |
161 | ```javascript
162 | var lyrics = 'Never gonna give you up, Never gonna let you down';
163 | ```
164 |
165 | * Если в строке встречается одинарная кавычка, она экранируется:
166 |
167 | ```javascript
168 | var test = 'It shouldn\'t fail';
169 | ```
170 |
171 | ##Точка с запятой
172 | Точка с запятой ставится всегда.
173 |
174 | ##Ключевые слова
175 | * Ключевые слова отделяются пробелом:
176 |
177 | ```javascript
178 | if (test) {
179 | // ...
180 | }
181 |
182 | function foo() {
183 | // ...
184 | }
185 |
186 | var bar = function () {
187 | // ...
188 | };
189 | ```
190 |
191 | * Перед точкой с запятой пробел не ставится:
192 |
193 | ```javascript
194 | return;
195 | ```
196 |
197 | ##Блочные инструкции
198 | * Открывающая фигурная скобка ставится на той же строке и отделяется пробелом от предыдущей конструкции:
199 |
200 | ```javascript
201 | if (test) {
202 | // ...
203 | }
204 |
205 | function foo() {
206 | // ...
207 | }
208 | ```
209 | * Фигурные скобки ставятся всегда:
210 |
211 | **Хорошо:**
212 |
213 | ```javascript
214 | if (test) {
215 | return;
216 | }
217 | ```
218 | **Плохо:**
219 |
220 | ```javascript
221 | if (test)
222 | return;
223 |
224 | if (test) return;
225 |
226 | if (test) { return; }
227 | ```
228 |
229 | ##Условные инструкции
230 | ###if
231 | * `else` пишется на той же строке, что и закрывающая фигурная скобка
232 |
233 | ```javascript
234 | if (test) {
235 | // ...
236 | } else {
237 | // ...
238 | }
239 | ```
240 | * Присваивание в условном выражении не используется:
241 |
242 | **Хорошо:**
243 |
244 | ```javascript
245 | var foo = bar();
246 | if (foo > 0) {
247 | // ...
248 | }
249 | ```
250 |
251 | **Плохо:**
252 | ```javascript
253 | var foo;
254 | if ((foo = bar()) > 0) {
255 | // ...
256 | }
257 | ```
258 | * Выражения используются только там, где требуется значение:
259 |
260 | **Хорошо:**
261 |
262 | ```javascript
263 | if (condition) {
264 | actionIfTrue();
265 | } else {
266 | actionIfFalse();
267 | }
268 | ```
269 |
270 | **Плохо:**
271 | ```javascript
272 | condition && actionIfTrue() || actionIfFalse();
273 | ```
274 |
275 | * Длинные условия, которые не вмещаются на одну строку, разбиваются следующим образом:
276 |
277 | ```javascript
278 | if (longCondition ||
279 | anotherLongCondition &&
280 | yetAnotherLongCondition
281 | ) {
282 | // ...
283 | }
284 | ```
285 |
286 | * [Yoda conditions](http://en.wikipedia.org/wiki/Yoda_conditions) не используются:
287 |
288 | **Хорошо:**
289 | ```javascript
290 | if (getType() === 'driving') {
291 |
292 | }
293 | ```
294 |
295 | **Плохо:**
296 | ```javascript
297 | if ('driving' === getType()) {
298 |
299 | }
300 | ```
301 |
302 | ###switch
303 |
304 | ```javascript
305 | switch (value) {
306 | case 1:
307 | // ...
308 | break;
309 |
310 | case 2:
311 | // ...
312 | break;
313 |
314 | default:
315 | // ...
316 | // no break keyword on the last case
317 | }
318 | ```
319 |
320 | ##Циклы
321 | ###for
322 | По возможности вместо `for` используется [Array.prototype.forEach](https://developer.mozilla.org/ru/docs/JavaScript/Reference/Global_Objects/Array/forEach):
323 |
324 | ```javascript
325 | [1, 2, 3].forEach(function (value) {
326 | console.log(value);
327 | });
328 | ```
329 |
330 | Код с использованием `forEach` проще читать (легче абстрагироваться от того, что происходит в каждой итерации). Где
331 | критична скорость используется обычный `for`.
332 |
333 | ###for (var i in obj)
334 | По возможности вместо `for-in` используется [Object.keys](https://developer.mozilla.org/ru/docs/JavaScript/Reference/Global_Objects/Object/keys):
335 | ```javascript
336 | Object.keys(obj).forEach(function (key) {
337 | console.log(key);
338 | });
339 | ```
340 |
341 | ##Операторы
342 | ###with
343 |
344 | Оператор `with` не используется.
345 |
346 | ###Оператор равенства
347 | Всегда используется строгое равенство `===` (неравенство `!==`), если нет необходимости в приведении типов.
348 |
349 | ###Тернарный оператор
350 |
351 | ```javascript
352 | var x = a ? b : c;
353 |
354 | var y = a ?
355 | longButSimpleOperandB : longButSimpleOperandC;
356 |
357 | var z = a ?
358 | moreComplicatedB :
359 | moreComplicatedC;
360 | ```
361 |
362 | ###Унарный оператор
363 | Все унарные операторы пишутся слитно с операндами:
364 |
365 | ```javascript
366 | var foo = !bar;
367 | ```
368 |
369 | ##eval
370 | Избегаем использования `eval`. Для парсинга `json` используется [JSON.parse](https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/JSON/parse).
371 |
372 | ##undefined
373 |
374 | Проверяем значение через строгое сравнение.
375 |
376 | **Хорошо:**
377 | ```javascript
378 | x === undefined;
379 | ```
380 |
381 | **Плохо:**
382 | ```javascript
383 | // в современных браузерах уже определен immutable undefined.
384 | var undefined;
385 | x === undefined;
386 |
387 | // больше писать
388 | typeof x === 'undefined'
389 |
390 | x === void 0
391 | ```
392 |
393 | ##Круглые скобки
394 | * Ставятся, если только это необходимо синтаксисом или семантикой.
395 | * Не используются с унарными операторами `delete`, `typeof` и `void`, а также ключевыми
396 | словами `return`, `throw`, `new`.
397 |
398 | ##Исключения
399 |
400 | Создаём исключения с помощью `new Error`:
401 |
402 | **Хорошо:**
403 | ```javascript
404 | throw new Error('msg');
405 | ```
406 | **Плохо:**
407 | ```javascript
408 | throw 'msg';
409 | ```
410 |
411 | ##Приведение типов
412 |
413 | Используются явные приведения типов:
414 |
415 | **Хорошо:**
416 | ```javascript
417 | Boolean(foo)
418 | Number(bar)
419 | String(baz)
420 | [].indexOf(qux) === -1 или [].indexOf(qux) < 0
421 | ```
422 | **Плохо:**
423 | ```javascript
424 | !!foo
425 | +bar
426 | baz + ''
427 | ~[].indexOf(qux)
428 | ```
429 |
430 | ##Переносы строк
431 | * Максимальная длина строки `120` символов, если строка выходит длиннее, то по возможности делаются переносы строки, с соответствующими отступами после переноса.
432 | * Операторы размещаются на предыдущей строке:
433 |
434 | ```javascript
435 | var debt = this.calculateBaseDebt() + this.calculateSharedDebt() + this.calculateDebtPayments() +
436 | this.calculateDebtFine();
437 | ```
438 |
439 | * Закрывающие скобки не прижимаются к переносимому коду:
440 |
441 | **Хорошо:**
442 | ```javascript
443 | DoSomethingThatRequiresALongFunctionName(
444 | veryLongArgument1,
445 | argument2,
446 | argument3,
447 | argument4
448 | );
449 | anotherStatement;
450 | ```
451 | **Плохо:**
452 | ```javascript
453 | DoSomethingThatRequiresALongFunctionName(
454 | veryLongArgument1,
455 | argument2,
456 | argument3,
457 | argument4);
458 | anotherStatement;
459 | ```
460 |
461 | ##Цепочки вызовов
462 | * При переносе вызова функции на новую строку:
463 | * Оператор доступа к свойству `.` ставится на новой строке.
464 | * Добавляется отступ относительно объекта, у которого вызывается функция.
465 |
466 | **Хорошо**:
467 |
468 | ```js
469 | someObject
470 | .operation()
471 | .operationWithCallback(function (obj) {
472 | obj.processed = true;
473 | })
474 | .end();
475 | ```
476 |
477 | **Плохо**:
478 |
479 | ```js
480 | someObject.
481 | start().
482 | end();
483 |
484 | someObject
485 | .start()
486 | .end();
487 | ```
488 |
489 | ##Конкатенация строк
490 | * Для конкатенации строк используется оператор `+`.
491 | * Конструкция `[].join('')` не используется (это было актуально для старых браузеров).
492 | * `\` не используется.
493 |
494 | **Хорошо:**
495 | ```javascript
496 | var foo = 'A rather long string of English text, an error message ' +
497 | 'actually that just keeps going and going -- an error ' +
498 | 'message to make the Energizer bunny blush (right through ' +
499 | 'those Schwarzenegger shades)! Where was I? Oh yes, ' +
500 | 'you\'ve got an error and all the extraneous whitespace is ' +
501 | 'just gravy. Have a nice day.';
502 | ```
503 | **Плохо:**
504 | ```javascript
505 | var foo = 'A rather long string of English text, an error message \
506 | actually that just keeps going and going -- an error \
507 | message to make the Energizer bunny blush (right through \
508 | those Schwarzenegger shades)! Where was I? Oh yes, \
509 | you\'ve got an error and all the extraneous whitespace is \
510 | just gravy. Have a nice day.';
511 | ```
512 |
513 | ##Пустые линии
514 | Могут использоваться для логической группировки частей кода:
515 |
516 | ```javascript
517 | doSomethingTo(x);
518 | doSomethingElseTo(x);
519 | andThen(x);
520 |
521 | nowDoSomethingWith(y);
522 |
523 | andNowWith(z);
524 | ```
525 |
526 | ##Контекст функции
527 |
528 | * Рекомендуется использовать `Function.prototype.bind`:
529 |
530 | ```javascript
531 | doAsync(function () {
532 | this.fn();
533 | }.bind(this));
534 | ```
535 |
536 | * Если функция позволяет передать `this` параметром, используем его:
537 |
538 | **Хорошо:**
539 |
540 | ```javascript
541 | [1, 2, 3].forEach(function (n) {
542 | this.fn(n);
543 | }, this);
544 | ```
545 |
546 | **Плохо:**
547 |
548 | ```javascript
549 | [1, 2, 3].forEach(function (n) {
550 | this.fn(n);
551 | }.bind(this));
552 | ```
553 |
554 | * Если используется переменная, называем ее `_this`:
555 |
556 | ```javascript
557 | var _this = this;
558 | doAsync(function () {
559 | _this.fn();
560 | });
561 | ```
562 |
563 | ##Комментарии
564 | * Для инлайновых комментариев используется `//`. После `//` ставится 1 пробел.
565 | * Комментарии к функциям, классам и т.п. пишутся в формате [jsdoc](http://usejsdoc.org/).
566 |
567 | ##Классы
568 | "Симметричные" методы размещаем рядом. Например:
569 |
570 | ```javascript
571 | var FooClass = inherit({
572 | __constructor: function () {},
573 |
574 | // деструктор рядом с конструктором
575 | destruct: function () {},
576 |
577 | someMethod: function () {}
578 | });
579 | ```
580 |
581 | ##node.js
582 |
583 | ###Импортирование модулей
584 |
585 | * Все модули импортируются в начале файла сразу после описания к нему, если оно есть:
586 |
587 | **Хорошо:**
588 |
589 | ```javascript
590 | var http = require('http');
591 | var fs = require('fs');
592 |
593 | // code here
594 | ```
595 | **Плохо:**
596 |
597 | ```javascript
598 | var http = require('http');
599 |
600 | // code here
601 |
602 | var fs = require('fs');
603 |
604 | // code here
605 | ```
606 |
607 | Исключение: модули, импортируемые по требованию.
608 |
609 | * Импорты должны быть сгруппированы в следующем порядке:
610 |
611 | 1. стандартные модули node.js
612 | 2. модули сторонних библиотек
613 | 3. модули вашего приложения
614 |
--------------------------------------------------------------------------------