renovations
|
@ -12,11 +12,11 @@
|
|||
|
||||
В вашей версии Chrome панель может выглядеть несколько по-иному, но что где находится, должно быть понятно.
|
||||
|
||||
Зайдите на страницу [debugging/pow/index.html](/debugging/pow/index.html) браузером Chrome.
|
||||
Зайдите на [страницу с примером](debugging/index.html) браузером Chrome.
|
||||
|
||||
Откройте инструменты разработчика: [key F12] или в меню `Инструменты > Инструменты Разработчика`.
|
||||
|
||||
Выберите сверху `Sources` (вместо иконок у вас могут быть просто надписи "Elements", "Resources", "Network", "Sources"...)
|
||||
Выберите сверху `Sources`.
|
||||
|
||||
<img src="chrome_sources.png">
|
||||
|
||||
|
@ -34,7 +34,7 @@
|
|||
|
||||
<img src="chrome_sources_buttons.png">
|
||||
|
||||
Три полезные кнопки управления:
|
||||
Три наиболее часто используемые кнопки управления:
|
||||
<dl>
|
||||
<dt>Формат <span class="devtools" style="background-position:-264px 94px"></span></dt>
|
||||
<dd>Нажатие форматирует текст текущего файла, расставляет отступы. Нужна, если вы хотите разобраться в чужом коде, плохо отформатированном или сжатом.</dd>
|
||||
|
@ -46,10 +46,12 @@
|
|||
|
||||
## Точки остановки
|
||||
|
||||
Открыли `pow.js` в зоне текста? Кликните на 6й строке файла `pow.js`, прямо на цифре 6.
|
||||
Открыли файл `pow.js` во вкладке Sources? Кликните на 6й строке файла `pow.js`, прямо на цифре 6.
|
||||
|
||||
Поздравляю! Вы поставили "точку остановки" или, как чаще говорят, "брейкпойнт".
|
||||
|
||||
Выглядет это должно примерно так:
|
||||
|
||||
<img src="chrome_sources_breakpoint.png">
|
||||
|
||||
Слово *Брейкпойнт* (breakpoint) -- часто используемый английский жаргонизм. Это то место в коде, где отладчик будет *автоматически* останавливать выполнение JavaScript, как только оно до него дойдёт.
|
||||
|
@ -62,9 +64,9 @@
|
|||
Вкладка Breakpoints очень удобна, когда код большой, она позволяет:
|
||||
|
||||
<ul>
|
||||
<li>Быстро перейти на место кода, где стоит брейкпойнт -- кликом на текст.</li>
|
||||
<li>Временно выключить брейкпойнт -- кликом на чекбокс.</li>
|
||||
<li>Быстро удалить брейкпойнт -- правым кликом на текст и выбором Remove...</li>
|
||||
<li>Быстро перейти на место кода, где стоит брейкпойнт кликом на текст.</li>
|
||||
<li>Временно выключить брейкпойнт кликом на чекбокс.</li>
|
||||
<li>Быстро удалить брейкпойнт правым кликом на текст и выбором Remove, и так далее.</li>
|
||||
</ul>
|
||||
|
||||
[smart header="Дополнительные возможности"]
|
||||
|
@ -89,7 +91,7 @@ function pow(x, n) {
|
|||
|
||||
## Остановиться и осмотреться
|
||||
|
||||
Наша функция выполняется сразу при загрузке страницы, так что самый простой способ активировать JavaScript -- перезагрузить её. Итак, нажимаем [key F5] (Windows, Linux) или [key Cmd+R] (Mac).
|
||||
Наша функция выполняется сразу при загрузке страницы, так что самый простой способ активировать отладчик JavaScript -- перезагрузить её. Итак, нажимаем [key F5] (Windows, Linux) или [key Cmd+R] (Mac).
|
||||
|
||||
Если вы сделали всё, как описано выше, то выполнение прервётся как раз на 6й строке.
|
||||
|
||||
|
@ -117,17 +119,19 @@ function pow(x, n) {
|
|||
|
||||
## Управление выполнением
|
||||
|
||||
Пришло время "погонять" скрипт и "оттрейсить" (от англ. trace, отслеживать) его работу.
|
||||
Пришло время, как говорят, "погонять" скрипт и "оттрейсить" (от англ. trace -- отслеживать) его работу.
|
||||
|
||||
Обратим внимание на панель управления справа-сверху, в ней есть 6 кнопок:
|
||||
|
||||
<dl>
|
||||
<dt><img style="vertical-align:middle" src="manage1.png"> -- продолжить выполнение, горячая клавиша [key F8].</dt>
|
||||
<dd> Если скрипт не встретит новых точек остановки, то на этом работа в отладчике закончится.
|
||||
<dd>Продолжает выполнения скрипта с текущего момента в обычном режиме. Если скрипт не встретит новых точек остановки, то в отладчик управление больше не вернётся.
|
||||
|
||||
Нажмите на эту кнопку.
|
||||
|
||||
Вы увидите, что отладчик остался на той же строке, но в `Call Stack` появился новый вызов. Это произошло потому, что в 6й строке находится рекурсивный вызов функции `pow`, т.е. управление перешло в неё опять, но с другими аргументами.
|
||||
Скрипт продолжится, далее, в 6й строке находится рекурсивный вызов функции `pow`, т.е. управление перейдёт в неё опять (с другими аргументами) и сработает точка остановки, вновь включая отладчик.
|
||||
|
||||
При этом вы увидите, что выполнение стоит на той же строке, но в `Call Stack` появился новый вызов.
|
||||
|
||||
Походите по стеку вверх-вниз -- вы увидите, что действительно аргументы разные.
|
||||
</dd>
|
||||
|
@ -162,17 +166,15 @@ function pow(x, n) {
|
|||
|
||||
**Процесс отладки заключается в том, что мы останавливаем скрипт, смотрим, что с переменными, переходим дальше и ищем, где поведение отклоняется от правильного.**
|
||||
|
||||
[smart header="Дополнительные возможности"]
|
||||
Правый клик на номер строки открывает контекстное меню, в котором можно запустить выполнение кода до неё (Continue to here).
|
||||
|
||||
Это очень удобно, если промежуточные строки нас не интересуют.
|
||||
[smart header="Continue to here"]
|
||||
Правый клик на номер строки открывает контекстное меню, в котором можно запустить выполнение кода до неё (Continue to here). Это удобно, когда хочется сразу прыгнуть вперёд и breakpoint неохота ставить.
|
||||
[/smart]
|
||||
|
||||
|
||||
|
||||
## Консоль
|
||||
|
||||
При отладке, кроме просмотра переменных, бывает полезно запускать команды JavaScript. Для этого нужна консоль.
|
||||
При отладке, кроме просмотра переменных и передвижения по скрипту, бывает полезно запускать команды JavaScript. Для этого нужна консоль.
|
||||
|
||||
В неё можно перейти, нажав кнопку "Console" вверху-справа, а можно и открыть в дополнение к отладчику, нажав на кнопку <span class="devtools" style="background-position:-72px -28px"></span> или клавишей [key ESC].
|
||||
|
||||
|
@ -190,13 +192,13 @@ for(var i=0; i<5; i++) {
|
|||
|
||||
Полную информацию по специальным командам консоли вы можете получить на странице [](https://developers.google.com/chrome-developer-tools/docs/commandline-api?hl=ru). Эти команды также действуют в Firebug (отладчик для браузера Firefox).
|
||||
|
||||
Консоль поддерживают все браузеры, и, хотя IE10- поддерживает далеко не все функции, `console.log` работает везде, пользуйтесь им вместо `alert`.
|
||||
Консоль поддерживают все браузеры, и, хотя IE10- поддерживает далеко не все функции, но `console.log` работает везде. Используйте его для вывода отладочной информации по ходу работы скрипта.
|
||||
|
||||
## Ошибки
|
||||
|
||||
Ошибки JavaScript выводятся в консоли.
|
||||
|
||||
Например, прервите отладку -- для этого достаточно закрыть инструменты разрабтчика -- и откройте страницу [debugging/pow-error/index.html](/debugging/pow-error/index.html).
|
||||
Например, прервите отладку -- для этого достаточно закрыть инструменты разрабтчика -- и откройте [страницу с ошибкой](error/index.html).
|
||||
|
||||
Перейдите во вкладку Console инструментов разработчика ([key Ctrl+Shift+J] / [key Cmd+Shift+J]).
|
||||
|
||||
|
|
Before Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 68 KiB |
Before Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 25 KiB |
19
1-js/3-writing-js/1-debugging-chrome/debugging.view/index.html
Executable file
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script src="pow.js"></script>
|
||||
|
||||
Пример для отладчика.
|
||||
|
||||
<script>
|
||||
var fiveInCube = pow(5, 3);
|
||||
|
||||
alert( fiveInCube );
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
8
1-js/3-writing-js/1-debugging-chrome/debugging.view/pow.js
Executable file
|
@ -0,0 +1,8 @@
|
|||
function pow(x, n) {
|
||||
if (n == 1) {
|
||||
return x;
|
||||
}
|
||||
|
||||
var result = x * pow(x, n-1);
|
||||
return result;
|
||||
}
|
19
1-js/3-writing-js/1-debugging-chrome/error.view/index.html
Executable file
|
@ -0,0 +1,19 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script src="pow.js"></script>
|
||||
|
||||
Пример для отладчика.
|
||||
|
||||
<script>
|
||||
var fiveInCube = pow(5, 3);
|
||||
|
||||
alert( fiveInCube );
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
8
1-js/3-writing-js/1-debugging-chrome/error.view/pow.js
Executable file
|
@ -0,0 +1,8 @@
|
|||
function pow(x, n) {
|
||||
if (n == 1) {
|
||||
return y;
|
||||
}
|
||||
|
||||
var result = x * pow(x, n-1);
|
||||
return result;
|
||||
}
|
Before Width: | Height: | Size: 717 B |
Before Width: | Height: | Size: 504 B |
Before Width: | Height: | Size: 431 B |
Before Width: | Height: | Size: 418 B |
Before Width: | Height: | Size: 554 B |
Before Width: | Height: | Size: 463 B |
|
@ -27,11 +27,13 @@ else // <- можно на одной строке } else {
|
|||
Исправленный вариант:
|
||||
|
||||
```js
|
||||
function pow(x,n) {
|
||||
var result = 1;
|
||||
function pow(x, n) {
|
||||
var result = 1;
|
||||
|
||||
for(var i = 0; i < n; i++) {
|
||||
result *=x;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,27 +5,70 @@
|
|||
[cut]
|
||||
## Синтаксис
|
||||
|
||||
Шпаргалка с правилами синтаксиса:
|
||||
Шпаргалка с правилами синтаксиса (детально они их варианты разобраны далее):
|
||||
|
||||
<img src="cheatsheet.png">
|
||||
|
||||
Разберём основные моменты.
|
||||
<img src="code-style.svg">
|
||||
|
||||
<!--
|
||||
```js
|
||||
function pow(x, n) {
|
||||
var result = 1;
|
||||
|
||||
for (var i = 0; i < n; i++) {
|
||||
result *=x;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
var x = prompt("x?", "");
|
||||
var n = prompt("n?", "");
|
||||
|
||||
if (n < 0) {
|
||||
alert('Степень ' + n +
|
||||
'не поддерживается, введите целую степень, большую 0');
|
||||
} else {
|
||||
alert( pow(x, n) );
|
||||
}
|
||||
```
|
||||
-->
|
||||
|
||||
|
||||
Не всё здесь однозначно, так что разберём эти правила подробнее.
|
||||
|
||||
### Фигурные скобки
|
||||
|
||||
Пишутся на той же строке, так называемый "египетский" стиль. Перед скобкой -- пробел.
|
||||
|
||||
<img src="figure.png">
|
||||
<!--
|
||||
```js
|
||||
if (n < 0) {alert('Степень ' + n + ' не поддерживается');}
|
||||
|
||||
Если у вас уже есть опыт в разработке и вы привыкли делать скобку на отдельной строке -- это тоже вариант. В конце концов, решать вам. Но в основных JavaScript-фреймворках (jQuery, Dojo, Google Closure Library, Mootools, Ext.JS, YUI...) стиль именно такой.
|
||||
|
||||
Если условие и код достаточно короткие, например `if (cond) return null;`, то запись в одну строку вполне читаема... Но, как правило, отдельная строка всё равно воспринимается лучше.
|
||||
|
||||
if (n < 0) alert('Степень ' + n + ' не поддерживается');
|
||||
|
||||
|
||||
|
||||
if (n < 0) {
|
||||
alert('Степень ' + n + ' не поддерживается');
|
||||
}
|
||||
|
||||
```
|
||||
-->
|
||||
|
||||
<img src="figure-bracket-style.svg">
|
||||
|
||||
Если у вас уже есть опыт в разработке и вы привыкли делать скобку на отдельной строке -- это тоже вариант. В конце концов, решать вам. Но в большинстве JavaScript-фреймворков стиль именно такой.
|
||||
|
||||
Если условие и код достаточно короткие, например `if (cond) return null`, то запись в одну строку вполне читаема... Но, как правило, отдельная строка всё равно воспринимается лучше.
|
||||
|
||||
### Длина строки
|
||||
|
||||
Максимальную длину строки согласовывают в команде. Как правило, это либо `80`, либо `120` символов, в зависимости от того, какие мониторы у разработчиков.
|
||||
|
||||
Более длинные строки необходимо разбивать. Если этого не сделать, то перевод очень длинной строки сделает редактор, и это может быть менее красиво и читаемо.
|
||||
Более длинные строки необходимо разбивать для улучшения читаемости.
|
||||
|
||||
### Отступы
|
||||
|
||||
|
@ -36,42 +79,29 @@
|
|||
|
||||
Как правило, используются именно пробелы, т.к. они позволяют сделать более гибкие "конфигурации отступов", чем символ "Tab".
|
||||
|
||||
Например:
|
||||
|
||||
Например, выровнять аргументы относительно открывающей скобки:
|
||||
```js
|
||||
function fib(n) {
|
||||
*!*
|
||||
var a = 1;
|
||||
var b = 1;
|
||||
*/!*
|
||||
for (var i = 3; i <= n; i++) {
|
||||
var c = a + b;
|
||||
a = b;
|
||||
b = c;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
show("Строки" +
|
||||
" выровнены" +
|
||||
" строго" +
|
||||
" одна под другой");
|
||||
```
|
||||
|
||||
Кстати, обратите внимание, переменные в выделенном фрагменте объявлены по вертикали, а не в строку `var a=1, b=1`. Так более наглядно, человеческий глаз лучше воспринимает ("сканирует") вертикально выравненную информацию, нежели по горизонтали. Это известный факт среди дизайнеров и нам, программистам, он тоже будет полезен для лучшей организации кода.
|
||||
|
||||
</li>
|
||||
<li>**Вертикальный отступ, для лучшей разбивки кода -- перевод строки.**
|
||||
|
||||
Используется, чтобы разделить логические блоки внутри одной функции. В примере ниже разделены функция `pow`, получение данных `x,n` и их обработка `if`.
|
||||
Используется, чтобы разделить логические блоки внутри одной функции. В примере разделены инициализация переменных, главный цикл и возвращение результата:
|
||||
|
||||
```js
|
||||
function pow(x, n) {
|
||||
return (n != 1) ? pow(x, n-1) : x;
|
||||
}
|
||||
// <--
|
||||
x = prompt(...);
|
||||
n = prompt(...);
|
||||
// <--
|
||||
if (n >= 1) {
|
||||
var result = pow(x, n);
|
||||
alert(result);
|
||||
var result = 1;
|
||||
// <--
|
||||
for (var i = 0; i < n; i++) {
|
||||
result *=x;
|
||||
}
|
||||
// <--
|
||||
return result;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Вставляйте дополнительный перевод строки туда, где это сделает код более читаемым. Не должно быть более 9 строк кода подряд без вертикального отступа.
|
||||
|
@ -82,9 +112,7 @@ if (n >= 1) {
|
|||
|
||||
Точки с запятой нужно ставить, даже если их, казалось бы, можно пропустить.
|
||||
|
||||
Есть языки, в которых точка с запятой не обязательна, и её там никто не ставит. В JavaScript она тоже не обязательна, но ставить нужно. В чём же разница?
|
||||
|
||||
Она в том, что **в JavaScript без точки с запятой возможны трудноуловимые ошибки.** С некоторыми примерами вы встретитесь дальше в учебнике. Такая вот особенность синтаксиса. И поэтому рекомендуется её всегда ставить.
|
||||
Есть языки, в которых точка с запятой не обязательна, и её там никто не ставит. В JavaScript перевод строки её заменяет, но лишь частично, поэтому лучше её ставить, как обсуждалось [ранее](#semicolon).
|
||||
|
||||
## Именование
|
||||
|
||||
|
@ -102,7 +130,7 @@ if (n >= 1) {
|
|||
|
||||
Уровней вложенности должно быть немного.
|
||||
|
||||
Например, [проверки в циклах лучше делать через "continue"](#continue), чтобы не было дополнительного уровня `if(..) { ... }`:
|
||||
Например, [проверки в циклах можно делать через "continue"](#continue), чтобы не было дополнительного уровня `if(..) { ... }`:
|
||||
|
||||
Вместо:
|
||||
|
||||
|
@ -159,21 +187,15 @@ function isEven(n) { // проверка чётности
|
|||
|
||||
В случае с функцией `isEven` можно было бы поступить и проще:
|
||||
|
||||
```js
|
||||
function isEven(n) { // проверка чётности
|
||||
return n % 2 == 0;
|
||||
}
|
||||
```
|
||||
|
||||
..Казалось бы, можно пойти дальше, есть ещё более короткий вариант:
|
||||
|
||||
```js
|
||||
function isEven(n) { // проверка чётности
|
||||
return !(n % 2);
|
||||
}
|
||||
```
|
||||
|
||||
...Однако, код `!(n % 2)` менее очевиден чем `n % 2 == 0`. Поэтому, на самом деле, последний вариант хуже. **Главное для нас -- не краткость кода, а его простота и читаемость.**
|
||||
...Однако, если код `!(n % 2)` для вас менее очевиден чем предыдущий вариант, то стоит использовать предыдущий.
|
||||
|
||||
Главное для нас -- не краткость кода, а его простота и читаемость. Совсем не всегда более короткий код проще для понимания, чем более развёрнутый.
|
||||
|
||||
## Функции = Комментарии
|
||||
|
||||
|
@ -185,7 +207,7 @@ function isEven(n) { // проверка чётности
|
|||
|
||||
Сравните, например, две функции `showPrimes(n)` для вывода простых чисел до `n`.
|
||||
|
||||
Первый вариант:
|
||||
Первый вариант использует метку:
|
||||
|
||||
```js
|
||||
function showPrimes(n) {
|
||||
|
@ -201,7 +223,7 @@ function showPrimes(n) {
|
|||
}
|
||||
```
|
||||
|
||||
Второй вариант, вынесена подфункция `isPrime(n)` для проверки на простоту:
|
||||
Второй вариант -- дополнительную функцию `isPrime(n)` для проверки на простоту:
|
||||
|
||||
```js
|
||||
function showPrimes(n) {
|
||||
|
@ -277,28 +299,41 @@ function walkAround() {
|
|||
</li>
|
||||
</ol>
|
||||
|
||||
...На самом деле существует еще третий "стиль", при котором функции хаотично разбросаны по коду ;), но это ведь не наш метод, да?
|
||||
...На самом деле существует еще третий "стиль", при котором функции хаотично разбросаны по коду, но это ведь не наш метод, да?
|
||||
|
||||
**Как правило, лучше располагать функции под кодом, который их использует.** То есть, это 2й способ.
|
||||
**Как правило, лучше располагать функции под кодом, который их использует.**
|
||||
|
||||
Дело в том, что при чтении такого кода мы хотим знать в первую очередь, *что он делает*, а уже затем *какие функции ему помогают.* Если первым идёт код, то это как раз дает необходимую информацию. Что же касается функций, то вполне возможно нам и не понадобится их читать, особенно если они названы адекватно и то, что они делают, понятно.
|
||||
То есть, предпочтителен 2й способ.
|
||||
|
||||
У первого способа, впрочем, есть то преимущество, что на момент чтения мы уже знаем, какие функции существуют.
|
||||
Дело в том, что при чтении такого кода мы хотим знать в первую очередь, *что он делает*, а уже затем *какие функции ему помогают.* Если первым идёт код, то это как раз дает необходимую информацию. Что же касается функций, то вполне возможно нам и не понадобится их читать, особенно если они названы адекватно и то, что они делают, понятно из названия.
|
||||
|
||||
Таким образом, если над названиями функций никто не думает -- может быть, это будет лучшим выбором :). Попробуйте оба варианта, но по моей практике предпочтителен всё же второй.
|
||||
|
||||
|
||||
## Комментарии
|
||||
## Плохие комментарии
|
||||
|
||||
В коде нужны комментарии.
|
||||
|
||||
**Как правило, комментарии отвечают на вопрос "что происходит в коде?"**
|
||||
Сразу начну с того, каких комментариев быть почти не должно.
|
||||
|
||||
**Должен быть минимум комментариев, которые отвечают на вопрос "что происходит в коде?"**
|
||||
|
||||
Что интересно, в коде начинающих разработчиков обычно комментариев либо нет, либо они как раз такого типа: "что делается в этих строках".
|
||||
|
||||
Серьёзно, хороший код и так понятен.
|
||||
|
||||
Об этом замечательно выразился Р.Мартин в книге ["Чистый код"](http://www.ozon.ru/context/detail/id/21916535/): "Если вам кажется, что нужно добавить комментарий для улучшения понимания, это значит, что ваш код недостаточно прост, и, может, стоит переписать его".
|
||||
|
||||
Если у вас образовалась длинная "простыня", то, возможно, стоит разбить её на отдельные функции, и тогда из их названий будет понятно, что делает тот или иной фрагмент.
|
||||
|
||||
Да, конечно, бывают сложные алгоритмы, хитрые решения для оптимизации, поэтому нельзя такие комментарии просто запретить. Но перед тем, как писать подобное -- подумайте: "Нельзя ли сделать код понятным и без них?"
|
||||
|
||||
## Хорошие комментарии
|
||||
|
||||
|
||||
А какие комментарии полезны и приветствуются?
|
||||
|
||||
Например:
|
||||
<ul>
|
||||
<li>**Архитектурный комментарий -- "как оно, вообще, устроено".**
|
||||
|
||||
Какие компоненты есть, какие технологии использованы, поток взаимодействия. О чём и зачем этот скрипт. Эти комментарии особенно нужны, если вы не один.
|
||||
Какие компоненты есть, какие технологии использованы, поток взаимодействия. О чём и зачем этот скрипт. Взгляд с высоты птичьего полёта. Эти комментарии особенно нужны, если вы не один, а проект большой.
|
||||
|
||||
Для описания архитектуры, кстати, создан специальный язык [UML](http://ru.wikipedia.org/wiki/Unified_Modeling_Language), красивые диаграммы, но можно и без этого. Главное -- чтобы понятно.
|
||||
</li>
|
||||
|
@ -319,18 +354,11 @@ function pow(x, n) {
|
|||
}
|
||||
```
|
||||
|
||||
Такие комментарии позволяют сразу понять, что принимает и что делает функция, не вникая в код.
|
||||
Такие комментарии позволяют сразу понять, что принимает и что делает функция, не вникая в код.
|
||||
|
||||
Кстати, они автоматически обрабатываются многими редакторами, например [Aptana](http://aptana.com) и редакторами от [JetBrains](http://www.jetbrains.com/), которые учитывают их при автодополнении.
|
||||
</li>
|
||||
<li>**Краткий комментарий, что именно происходит в данном блоке кода.**
|
||||
|
||||
Что интересно, в коде начинающих разработчиков обычно комментариев либо нет, либо они как раз такого типа: "что делается в этих строках кода".
|
||||
|
||||
На самом деле именно эти комментарии, как правило, являются самыми ненужными. Хороший код и так самоочевиден, если не используются особо сложные алгоритмы.
|
||||
|
||||
Об этом замечательно выразился Р. Мартин в книге ["Чистый код"](http://www.ozon.ru/context/detail/id/21916535/): "Если вам кажется, что нужно добавить комментарий для улучшения понимания, это значит, что ваш код не достаточно прост, и, может, стоит переписать его".
|
||||
Кстати, они автоматически обрабатываются многими редакторами, например [Aptana](http://aptana.com) и редакторами от [JetBrains](http://www.jetbrains.com/), которые учитывают их при автодополнении, а также выводят их в автоподсказках при наборе кода.
|
||||
|
||||
Кроме того, есть инструменты, например [JSDoc 3](https://github.com/jsdoc3/jsdoc), которые умеют генерировать по таким комментариям документацию в формате HTML. Более подробную информацию об этом можно также найти на сайте [](http://usejsdoc.org/).
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
@ -342,9 +370,9 @@ function pow(x, n) {
|
|||
|
||||
Например:
|
||||
|
||||
<ul>
|
||||
<li>**Есть несколько способов решения задачи. Почему выбран именно этот?**
|
||||
|
||||
<dl>
|
||||
<dt>Есть несколько способов решения задачи. Почему выбран именно этот?</dt>
|
||||
<dd>
|
||||
Например, пробовали решить задачу по-другому, но не получилось -- напишите об этом. Почему вы выбрали именно этот способ решения? Особенно это важно в тех случаях, когда используется не первый приходящий в голову способ, а какой-то другой.
|
||||
|
||||
Без этого возможна, например, такая ситуация:
|
||||
|
@ -354,18 +382,18 @@ function pow(x, n) {
|
|||
<li>...Порыв, конечно, хороший, да только этот вариант вы уже обдумали раньше. И отказались, а почему -- забыли. В процессе переписывания вспомнили, конечно (к счастью), но результат - потеря времени на повторное обдумывание.</li>
|
||||
</ul>
|
||||
|
||||
Комментарии, которые объясняют поведение кода, очень важны. Они помогают понять происходящее и принять правильное решение о развитии кода.
|
||||
|
||||
</li>
|
||||
<li>**Какие неочевидные возможности обеспечивает этот код?** Где в другом месте кода они используются?
|
||||
|
||||
Комментарии, которые объясняют выбор решения, очень важны. Они помогают понять происходящее и предпринять правильные шаги при развитии кода.
|
||||
</dd>
|
||||
<dt>Какие неочевидные возможности обеспечивает этот код? Где ещё они используются?</dt>
|
||||
<dd>
|
||||
В хорошем коде должно быть минимум неочевидного. Но там, где это есть -- пожалуйста, комментируйте.
|
||||
</li>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
</ul>
|
||||
|
||||
[smart header="Комментарии -- это важно"]
|
||||
Один из показателей хорошего разработчика -- качество комментариев, которые позволяют эффективно поддерживать код, возвращаться к нему после любой паузы и легко вносить изменения.
|
||||
|
||||
[/smart]
|
||||
|
||||
## Руководства по стилю
|
||||
|
||||
|
@ -382,21 +410,23 @@ function pow(x, n) {
|
|||
<li>[Dojo Style Guide](http://dojotoolkit.org/community/styleGuide)</li>
|
||||
</ul>
|
||||
|
||||
Для того, чтобы начать разработку, вполне хватит элементов стилей, обозначенных в этой главе. В дальнейшем, посмотрите на эти руководства, найдите "свой" стиль ;)
|
||||
Для того, чтобы начать разработку, вполне хватит элементов стилей, обозначенных в этой главе. В дальнейшем, посмотрев эти руководства, вы можете выработать и свой стиль, но лучше не делать его особенно "уникальным и неповторимым", себе дороже потом будет с людьми сотрудничать.
|
||||
|
||||
### Автоматизированные средства проверки
|
||||
|
||||
Существуют онлайн-сервисы, проверяющие стиль кода.
|
||||
Существуют средства, проверяющие стиль кода.
|
||||
|
||||
Самые известные -- это:
|
||||
|
||||
<ul>
|
||||
<li>[JSLint](http://www.jslint.com/) -- проверяет код на соответствие [стилю JSLint](http://www.jslint.com/lint.html), в онлайн-интерфейсе вверху можно ввести код, а внизу различные настройки проверки, чтобы сделать её более мягкой. </li>
|
||||
<li>[JSHint](http://www.jshint.com/) -- ещё один вариант JSLint, ослабляющий требования в ряде мест.</li>
|
||||
<li>[JSHint](http://www.jshint.com/) -- вариант JSLint с большим количеством настроек.</li>
|
||||
<li>[Closure Linter](https://developers.google.com/closure/utilities/) -- проверка на соответствие [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml).</li>
|
||||
</ul>
|
||||
|
||||
Все они также доступны в виде программ, которые можно скачать.
|
||||
В частности, JSLint и JSHint интегрированы с большинством редакторов, они гибко настраиваются под нужный стиль и совершенно незаметно улучшают разработку, подсказывая, где и что поправить.
|
||||
|
||||
Побочный эффект -- они видят некоторые ошибки, например необъявленные переменные. У меня это обычно результат опечатки, которые таким образом сразу отлавливаются. Очень рекомендую поставить что-то из этого. Я использую [JSHint](http://www.jshint.com/).
|
||||
|
||||
## Итого
|
||||
|
||||
|
|
Before Width: | Height: | Size: 38 KiB |
94
1-js/3-writing-js/2-coding-style/code-style.svg
Normal file
After Width: | Height: | Size: 125 KiB |
32
1-js/3-writing-js/2-coding-style/figure-bracket-style.svg
Normal file
After Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 17 KiB |
|
@ -1,18 +1,26 @@
|
|||
# Как писать неподдерживаемый код?
|
||||
|
||||
[warn header="Познай свой код"]
|
||||
Эта статья представляет собой мой вольный перевод [How To Write Unmaintainable Code](http://mindprod.com/jgloss/unmain.html) ("как писать неподдерживаемый код") с дополнениями, актуальными для JavaScript.
|
||||
|
||||
Возможно, в каких-то из этих советов вам даже удастся узнать "этого парня в зеркале".
|
||||
[/warn]
|
||||
|
||||
|
||||
Предлагаю вашему вниманию советы мастеров древности, следование которым создаст дополнительные рабочие места для JavaScript-разработчиков.
|
||||
|
||||
Если вы будете им следовать, то ваш код будет так сложен в поддержке, что у JavaScript'еров, которые придут после вас, даже простейшее изменение займет годы *оплачиваемого* труда! А сложные задачи оплачиваются хорошо, так что они, определённо, скажут вам "Спасибо".
|
||||
|
||||
Более того, *внимательно* следуя этим правилам, вы сохраните и своё рабочее место, так как все будут бояться вашего кода и бежать от него...
|
||||
|
||||
...Впрочем, всему своя мера. При написании такого кода он не должен *выглядеть* сложным в поддержке, код должен *быть* таковым. Явно кривой код может написать любой дурак. Это заметят, и вас уволят, а код будет переписан с нуля. Вы не можете такого допустить. Эти советы учитывают такую возможность. Да здравствует дзен.
|
||||
...Впрочем, всему своя мера. При написании такого кода он не должен *выглядеть* сложным в поддержке, код должен *быть* таковым.
|
||||
|
||||
Явно кривой код может написать любой дурак. Это заметят, и вас уволят, а код будет переписан с нуля. Вы не можете такого допустить. Эти советы учитывают такую возможность. Да здравствует дзен.
|
||||
|
||||
Статья представляет собой мой вольный перевод [How To Write Unmaintainable Code](http://mindprod.com/jgloss/unmain.html) с дополнениями, актуальными для JavaScript.
|
||||
|
||||
[cut]
|
||||
|
||||
## Соглашения
|
||||
## Соглашения -- по настроению
|
||||
|
||||
[quote author="Сериал \"Симпсоны\", серия Helter Shelter"]
|
||||
Рабочий-чистильщик осматривает дом:<br>
|
||||
|
@ -31,22 +39,26 @@
|
|||
|
||||
Как затруднить задачу? Можно везде нарушать соглашения -- это помешает ему, но такое могут заметить, и код будет переписан. Как поступил бы ниндзя на вашем месте?
|
||||
|
||||
**...Правильно! Следуйте соглашениям "в общем", но иногда -- нарушайте их.** Тщательно разбросанные по коду нарушения соглашений с одной стороны не делают код явно плохим при первом взгляде, а с другой -- имеют в точности тот же, и даже лучший эффект, чем явное неследование им!
|
||||
**...Правильно! Следуйте соглашениям "в общем", но иногда -- нарушайте их.**
|
||||
|
||||
Если пример, который я приведу ниже, пока сложноват -- пропустите его, но обязательно вернитесь к нему позже. Поверьте, это стоит того.
|
||||
Тщательно разбросанные по коду нарушения соглашений с одной стороны не делают код явно плохим при первом взгляде, а с другой -- имеют в точности тот же, и даже лучший эффект, чем явное неследование им!
|
||||
|
||||
### Пример из jQuery
|
||||
|
||||
[warn header="jQuery / DOM"]
|
||||
Этот пример требует знаний jQuery/DOM, если пока их у вас нет -- пропустите его, ничего страшного, но обязательно вернитесь к нему позже. Подобное стоит многих часов отладки.
|
||||
[/warn]
|
||||
Во фреймворке jQuery есть метод [wrap](http://api.jquery.com/wrap/), который обёртывает один элемент вокруг другого:
|
||||
|
||||
```js
|
||||
var img = $('<img/>'); // создали новые элементы (jQuery-синтаксис)
|
||||
var div = $('<div/>'); // и поместили в переменную
|
||||
|
||||
*!*
|
||||
img.wrap(div); // обернуть img в div
|
||||
*/!*
|
||||
div.append('<span/>');
|
||||
```
|
||||
|
||||
Результат кода выше -- два элемента, один вложен в другой:
|
||||
Результат кода после операции `wrap` -- два элемента, один вложен в другой:
|
||||
|
||||
```html
|
||||
<div>
|
||||
|
@ -54,66 +66,24 @@ img.wrap(div); // обернуть img в div
|
|||
</div>
|
||||
```
|
||||
|
||||
(`div` обернулся вокруг `img`)
|
||||
А что же после `append`?
|
||||
|
||||
А теперь, когда все расслабились и насладились этим замечательным методом...
|
||||
Можно предположить, что `<span/>` добавится в конец `div`, сразу после `img`... Но ничего подобного!
|
||||
|
||||
...Самое время ниндзя нанести свой удар!
|
||||
Искусный ниндзя уже нанёс свой удар и поведение кода стало неправильным, хотя разработчик об этом даже не подозревает.
|
||||
|
||||
**Как вы думаете, что будет, если добавить к коду выше строку:**
|
||||
Как правило, методы jQuery работают с теми элементами, которые им переданы. Но не здесь!
|
||||
|
||||
```js
|
||||
//+ lines first-line=5
|
||||
div.append('<span/>');
|
||||
```
|
||||
Внутри вызова `img.wrap(div)` происходит клонирование `div` и вокруг `img` оборачивается не сам `div`, а его клон. При этом исходная переменная `div` не меняется, в ней как был пустой `div`, так и остался.
|
||||
|
||||
[smart header="jQuery-справка"]
|
||||
Вызов `elemA.append(elemB)` добавляет `elemB` в конец содержимого элемента `elemA`.
|
||||
[/smart]
|
||||
В итоге, после вызова получается два независимых `div'а`: первый содержит `img` (этот неявный клон никуда не присвоен), а второй -- наш `span`.
|
||||
|
||||
**Возможно, вы полагаете, что `<span/>` добавится в конец `div`, сразу после `img`?**
|
||||
Злая магия? Плохой феншуй?
|
||||
|
||||
А вот и нет! А вот и нет!..
|
||||
Ничего подобного, просто избирательное следование соглашениям. Вызов `wrap` -- неявно клонирует элемент.
|
||||
|
||||
Оказывается, внутри вызова `img.wrap(div)` происходит *клонирование* `div`. И вокруг `img` оборачивается не сам `div`, а его <strike>злой</strike> клон.
|
||||
Такой сюрприз, бесспорно, стоит многих часов отладки.
|
||||
|
||||
При этом исходная переменная `div` не меняется, в ней как был пустой `div`, так и остался. В итоге, после применения к нему `append` получается два `div'а`: один обёрнут вокруг `span`, а в другом -- только `img`.
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
|
||||
<th>Переменная `div`</th>
|
||||
<th>Клон `div`, созданный `wrap`
|
||||
(не присвоен никакой переменной)</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
|
||||
```html
|
||||
<div>
|
||||
<span/>
|
||||
</div>
|
||||
```
|
||||
|
||||
</td>
|
||||
<td>
|
||||
|
||||
```html
|
||||
<div>
|
||||
<img/>
|
||||
</div>
|
||||
```
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Странно? Неочевидно? Да, и не только вам :)
|
||||
|
||||
Соглашение в данном случае -- в том, что большинство методов jQuery не клонируют элементы. А вызов `wrap` -- клонирует.
|
||||
|
||||
Код его истинный ниндзя писал!
|
||||
|
||||
## Краткость -- сестра таланта!
|
||||
|
||||
|
@ -148,7 +118,7 @@ i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0;
|
|||
|
||||
Остановите свой взыскательный взгляд на чём-нибудь более экзотическом. Например, `x` или `y`.
|
||||
|
||||
Эффективность этого подхода особенно заметна, если тело цикла занимает одну-две страницы.
|
||||
Эффективность этого подхода особенно заметна, если тело цикла занимает одну-две страницы (чем длиннее -- тем лучше).
|
||||
|
||||
В этом случае заметить, что переменная -- счетчик цикла, без пролистывания вверх, невозможно.
|
||||
|
||||
|
@ -281,7 +251,7 @@ function ninjaFunction(elem) {
|
|||
var *!*user*/!* = authenticateUser();
|
||||
|
||||
function render() {
|
||||
var *!*user*/!* = ...
|
||||
var *!*user*/!* = anotherValue();
|
||||
...
|
||||
...многобукв...
|
||||
...
|
||||
|
@ -290,7 +260,7 @@ function render() {
|
|||
}
|
||||
```
|
||||
|
||||
Зашедший в середину метода `render` программист, скорее всего, не заметит, что переменная `user` "уже не та" и использует её... Ловушка захлопнулась! Здравствуй, отладчик.
|
||||
Зашедший в середину метода `render` программист, скорее всего, не заметит, что переменная `user` локально перекрыта и попытается работать с ней, полагая, что это результат `authenticateUser()`... Ловушка захлопнулась! Здравствуй, отладчик.
|
||||
|
||||
## Мощные функции!
|
||||
|
||||
|
@ -298,7 +268,9 @@ function render() {
|
|||
|
||||
Например, функция `validateEmail(email)` может, кроме проверки e-mail на правильность, выводить сообщение об ошибке и просить заново ввести e-mail.
|
||||
|
||||
**Выберите хотя бы пару дополнительных действий, кроме основного назначения функции.** Главное -- они должны быть неочевидны из названия функции. Истинный ниндзя-девелопер сделает так, что они будут неочевидны и из кода тоже.</li>
|
||||
**Выберите хотя бы пару дополнительных действий, кроме основного назначения функции.**
|
||||
|
||||
Главное -- они должны быть неочевидны из названия функции. Истинный ниндзя-девелопер сделает так, что они будут неочевидны и из кода тоже.</li>
|
||||
|
||||
**Объединение нескольких смежных действий в одну функцию защитит ваш код от повторного использования.**
|
||||
|
||||
|
@ -315,9 +287,9 @@ function render() {
|
|||
|
||||
**Ещё одна вариация такого подхода -- возвращать нестандартное значение.**
|
||||
|
||||
Ведь общеизвестно, что `is..` и `check..` обычно возвращают `true/false`. Продемонстрируйте оригинальное мышление. Пусть вызов `checkPermission` возвращает не результат `true/false`, а объект -- с результатами проверки! А что, полезно.
|
||||
Ведь общеизвестно, что `is..` и `check..` обычно возвращают `true/false`. Продемонстрируйте оригинальное мышление. Пусть вызов `checkPermission` возвращает не результат `true/false`, а объект с результатами проверки! А чего, полезно.
|
||||
|
||||
Те разработчики, кто попытается написать проверку `if (checkPermission(..))`, будут весьма удивлены результатом. Ответьте им: "надо читать документацию!". И перешлите эту статью.
|
||||
Те же разработчики, кто попытается написать проверку `if (checkPermission(..))`, будут весьма удивлены результатом. Ответьте им: "надо читать документацию!". И перешлите эту статью.
|
||||
|
||||
## Заключение
|
||||
|
||||
|
|
|
@ -8,13 +8,11 @@
|
|||
|
||||
При написании функции мы обычно представляем, что она должна делать, какое значение -- на каких аргументах выдавать.
|
||||
|
||||
В процессе разработки мы, время от времени, проверяем функцию. Самый простой способ проверки -- это запустить функцию и посмотреть результат.
|
||||
В процессе разработки мы, время от времени, проверяем, правильно ли работает функция. Самый простой способ проверить -- это запустить её, например, в консоли, и посмотреть результат.
|
||||
|
||||
Потом написать ещё код, попробовать запустить -- опять посмотреть результат.
|
||||
Если что-то не так -- поправить, опять запустить -- посмотреть результат... И так -- "до победного конца".
|
||||
|
||||
И так -- "до победного конца".
|
||||
|
||||
К сожалению, такие ручные запуски -- очень несовершенное средство проверки.
|
||||
Но такие ручные запуски -- очень несовершенное средство проверки.
|
||||
|
||||
**Когда проверяешь работу кода вручную -- легко его "недотестировать".**
|
||||
|
||||
|
@ -28,15 +26,14 @@
|
|||
|
||||
BDD -- это не просто тесты. Это гораздо больше.
|
||||
|
||||
**Тесты BDD -- это три в одном: это И тесты И документация И примеры использования одновременно.**
|
||||
**Тесты BDD -- это три в одном: И тесты И документация И примеры использования одновременно.**
|
||||
|
||||
Впрочем, хватит слов. Рассмотрим примеры.
|
||||
|
||||
## Разработка pow
|
||||
## Разработка pow: спецификация
|
||||
|
||||
Допустим, мы хотим разработать функцию `pow(x, n)`, которая возводит `x` в целую степень `n`, для простоты `n≥0`.
|
||||
|
||||
### Спецификация
|
||||
|
||||
Ещё до разработки мы можем представить себе, что эта функция будет делать и описать это по методике BDD.
|
||||
|
||||
|
@ -61,9 +58,15 @@ describe("pow", function() {
|
|||
<dt>`assert.equal(value1, value2)`</dt>
|
||||
<dd>Код внутри `it`, если реализация верна, должен выполняться без ошибок.
|
||||
|
||||
Для того, чтобы проверить, делает ли `pow` то, что задумано, используются функции вида `assert.*`. Пока что нас интересует только одна из них -- `assert.equal`, она сравнивает свой первый аргумент со вторым и выдаёт ошибку в случае, когда они не равны. Есть и другие виды сравнений и проверок, которые мы увидим далее.</dd>
|
||||
Различные функции вида `assert.*` используются, чтобы проверить, делает ли `pow` то, что задумано. Пока что нас интересует только одна из них -- `assert.equal`, она сравнивает свой первый аргумент со вторым и выдаёт ошибку в случае, когда они не равны. В данном случае она проверяет, что результат `pow(2, 3)` равен `8`.
|
||||
|
||||
|
||||
Есть и другие виды сравнений и проверок, которые мы увидим далее.</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
## Поток разработки
|
||||
|
||||
Как правило, поток разработки таков:
|
||||
<ol>
|
||||
<li>Пишется спецификация, которая описывает самый базовый функционал.</li>
|
||||
|
@ -77,7 +80,7 @@ describe("pow", function() {
|
|||
|
||||
В нашем случае первый шаг уже завершён, начальная спецификация готова, хорошо бы приступить к реализации. Но перед этим проведём "нулевой" запуск спецификации, просто чтобы увидеть, что уже в таком виде, даже без реализации -- тесты работают.
|
||||
|
||||
### Проверка спецификации
|
||||
## Пример в действии
|
||||
|
||||
Для запуска тестов нужны соответствующие JavaScript-библиотеки.
|
||||
|
||||
|
@ -96,22 +99,23 @@ describe("pow", function() {
|
|||
<!--+ src="index.html" -->
|
||||
```
|
||||
|
||||
Эту страницу можно условно разделить на три части:
|
||||
Эту страницу можно условно разделить на четыре части:
|
||||
<ol>
|
||||
<li>В `<head>` подключаем библиотеки и стили.</li>
|
||||
<li>Подключаем `<script>` с реализацией, в нашем случае -- с кодом для `pow`. Пока что функции нет, мы лишь готовимся её написать.</li>
|
||||
<li>Далее подключаются тесты, файл `test.js` содержит `describe("pow", ...)`, который был описан выше. Методы `describe` и `it` принадлежат библиотеке Mocha, так что важно, что она была подключена выше. Их вызов добавляет тесты, для запуска которых используется команда `mocha.run()`. Она выведет результат тестов в элемент с `id="mocha"`.</li>
|
||||
<li>Блок `<head>` -- в нём мы подключаем библиотеки и стили для тестирования, нашего кода там нет.</li>
|
||||
<li>Блок `<script>` с реализацией спецификации, в нашем случае -- с кодом для `pow`.</li>
|
||||
<li>Далее подключаются тесты, файл `test.js` содержит `describe("pow", ...)`, который был описан выше. Методы `describe` и `it` принадлежат библиотеке Mocha, так что важно, что она была подключена выше.</li>
|
||||
<li>Элемент `<div id="mocha">` будет использоваться библиотекой Mocha для вывода результатов. Запуск тестов инициируется командой `mocha.run()`.</li>
|
||||
</ol>
|
||||
|
||||
Результат срабатывания:
|
||||
|
||||
[iframe height=250 src="pow-1" border=1 edit]
|
||||
|
||||
Пока что тесты не проходят, но это логично -- вместо функции стоит "заглушка", пустой код.
|
||||
|
||||
Пока что у нас одна функция и одна спецификация, но на будущее заметим, что если различных функций и тестов много -- это не проблема, можно их все подключить на одной странице. Конфликта не будет, так как каждый функционал имеет свой блок `describe("что тестируем"...)`. Сами же тесты обычно пишутся так, чтобы не влиять друг на друга, не делать лишних глобальных переменных.
|
||||
|
||||
Посмотрели, попробовали запустить у себя что-то подобное? Если да -- идём дальше.
|
||||
|
||||
### Начальная реализация
|
||||
## Начальная реализация
|
||||
|
||||
Пока что, как видно, тесты не проходят, ошибка сразу же. Давайте сделаем минимальную реализацию `pow`, которая бы работала нормально:
|
||||
|
||||
|
@ -125,7 +129,7 @@ function pow() {
|
|||
|
||||
[iframe height=250 src="pow-min" border=1 edit]
|
||||
|
||||
### Расширение спецификации
|
||||
## Исправление спецификации
|
||||
|
||||
Функция, конечно, ещё не готова, но тесты проходят. Это ненадолго :)
|
||||
|
||||
|
@ -192,9 +196,9 @@ describe("pow", function() {
|
|||
|
||||
Как и следовало ожидать, второй тест не проходит. Ещё бы, ведь функция всё время возвращает `8`.
|
||||
|
||||
### Уточнение реализации
|
||||
## Уточнение реализации
|
||||
|
||||
Придётся написать нечто более реальное:
|
||||
Придётся написать нечто более реальное, чтобы тесты проходили:
|
||||
|
||||
```js
|
||||
function pow(x, n) {
|
||||
|
@ -231,7 +235,7 @@ describe("pow", function() {
|
|||
[iframe height=250 src="pow-3" edit border="1"]
|
||||
|
||||
|
||||
### Вложенный describe
|
||||
## Вложенный describe
|
||||
|
||||
Функция `makeTest` и цикл `for`, очевидно, нужны друг другу, но не нужны для других тестов, которые мы добавим в дальнейшем. Они образуют единую группу, задача которой -- проверить возведение в `n`-ю степень.
|
||||
|
||||
|
@ -307,9 +311,9 @@ describe("Тест", function() {
|
|||
Как правило, `beforeEach/afterEach` (`before/each`) используют, если необходимо произвести инициализацию, обнулить счётчики или сделать что-то ещё в таком духе между тестами (или их группами).
|
||||
[/smart]
|
||||
|
||||
### Расширение спецификации
|
||||
## Расширение спецификации
|
||||
|
||||
Базовый функционал описан и реализован, первая итерация разработки завершена. Теперь расширим и уточним его.
|
||||
Базовый функционал `pow` описан и реализован, первая итерация разработки завершена. Теперь расширим и уточним его.
|
||||
|
||||
Как говорилось ранее, функция `pow(x, n)` предназначена для работы с целыми неотрицательными `n`.
|
||||
|
||||
|
@ -342,7 +346,7 @@ describe("pow", function() {
|
|||
|
||||
Конечно, новые тесты не проходят, так как наша реализация ещё не поддерживает их. Так и задумано: сначала написали заведомо не работающие тесты, а затем пишем реализацию под них.
|
||||
|
||||
### Другие assert
|
||||
## Другие assert
|
||||
|
||||
Обратим внимание, в спецификации выше использована проверка не `assert.equal`, как раньше, а `assert(выражение)`. Такая проверка выдаёт ошибку, если значение выражения при приведении к логическому типу не `true`.
|
||||
|
||||
|
@ -352,7 +356,7 @@ describe("pow", function() {
|
|||
|
||||
Однако, между этими вызовами есть отличие в деталях сообщения об ошибке.
|
||||
|
||||
При `assert` мы видим `Unspecified AssertionError`, то есть просто "что-то пошло не так", а при `assert.equal(value1, value2)` -- будут дополнительные подробности: `expected 8 to equal 81`.
|
||||
При "упавшем" `assert` в примере выше мы видим `"Unspecified AssertionError"`, то есть просто "что-то пошло не так", а при `assert.equal(value1, value2)` -- будут дополнительные подробности: `expected 8 to equal 81`.
|
||||
|
||||
**Поэтому рекомендуется использовать именно ту проверку, которая максимально соответствует задаче.**
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
describe("Тест", function() {
|
||||
|
||||
before(function() { alert("Начало тестов"); });
|
||||
after(function() { alert("Конец тестов"); });
|
||||
before(function() { alert("Начало всех тестов"); });
|
||||
after(function() { alert("Окончание всех тестов"); });
|
||||
|
||||
beforeEach(function() { alert("Вход в тест"); });
|
||||
afterEach(function() { alert("Выход из теста"); });
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
describe("pow", function() {
|
||||
|
||||
describe("возводит x в степень n", function() {
|
||||
|
||||
function makeTest(x) {
|
||||
var expected = x*x*x;
|
||||
it("при возведении "+x+" в степень 3 результат: " + expected, function() {
|
||||
assert.equal( pow(x, 3), expected);
|
||||
});
|
||||
}
|
||||
|
||||
for(var x = 1; x <= 5; x++) {
|
||||
makeTest(x);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
it("при возведении в отрицательную степень результат NaN", function() {
|
||||
assert( isNaN( pow(2, -1) ), "pow(2, -1) не NaN" );
|
||||
});
|
||||
|
||||
it("при возведении в дробную степень результат NaN", function() {
|
||||
assert( isNaN( pow(2, 1.5) ), "pow(2, -1.5) не NaN" );
|
||||
});
|
||||
|
||||
describe("любое число, кроме нуля, в степени 0 равно 1", function() {
|
||||
|
||||
function makeTest(x) {
|
||||
it("при возведении " + x + " в степень 0 результат: 1", function() {
|
||||
assert.equal( pow(x, 0), 1);
|
||||
});
|
||||
}
|
||||
|
||||
for(var x = -5; x <= 5; x+=2) {
|
||||
makeTest(x);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
it("ноль в нулевой степени даёт NaN", function() {
|
||||
assert( isNaN( pow(0,0) ), "0 в степени 0 не NaN");
|
||||
});
|
||||
|
||||
});
|