└── 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 | --------------------------------------------------------------------------------