Выразительный JavaScript (Хавербеке) - страница 30

>  console.log(numberString + " " + label);

>}


>// вывестиИнвентаризациюФермы

>function printFarmInventory(cows, chickens, pigs) {

>  printZeroPaddedWithLabel(cows, "Коров");

>  printZeroPaddedWithLabel(chickens, "Куриц");

>  printZeroPaddedWithLabel(pigs, "Свиней");

>}


>printFarmInventory(7, 11, 3);

Работает! Но название >printZeroPaddedWithLabel немного странное. Оно объединяет три вещи – вывод, добавление нулей и метку – в одну функцию. Вместо того, чтобы вставлять в функцию весь повторяющийся фрагмент, давайте выделим одну концепцию:

>// добавитьНулей

>function zeroPad(number, width) {

>  var string = String(number);

>  while (string.length < width)

>    string = "0" + string;

>  return string;

>}


>// вывестиИнвентаризациюФермы

>function printFarmInventory(cows, chickens, pigs) {

>  console.log(zeroPad(cows, 3) + " Коров");

>  console.log(zeroPad(chickens, 3) + " Куриц");

>  console.log(zeroPad(pigs, 3) + " Свиней");

>}


>printFarmInventory(7, 16, 3);

Функция с хорошим, понятным именем >zeroPad облегчает понимание кода. И её можно использовать во многих ситуациях, не только в нашем случае. К примеру, для вывода отформатированных таблиц с числами.

Насколько умными и универсальными должны быть функции? Мы можем написать как простейшую функцию, которая дополняет число нулями до трёх позиций, так и навороченную функцию общего назначения для форматирования номеров, поддерживающую дроби, отрицательные числа, выравнивание по точкам, дополнение разными символами, и т. п.

Хорошее правило – добавляйте только ту функциональность, которая вам точно пригодится. Иногда появляется искушение создавать фреймворки общего назначения для каждой небольшой потребности. Сопротивляйтесь ему. Вы никогда не закончите работу, а просто напишете кучу кода, который никто не будет использовать.

Функции и побочные эффекты

Функции можно грубо разделить на те, что вызываются из-за своих побочных эффектов, и те, что вызываются для получения некоторого значения. Конечно, возможно и объединение этих свойств в одной функции.

Первая вспомогательная функция в примере с фермой, >printZeroPaddedWithLabel, вызывается из-за побочного эффекта: она выводит строку. Вторая, >zeroPad, из-за возвращаемого значения. И это не совпадение, что вторая функция пригождается чаще первой. Функции, возвращающие значения, легче комбинировать друг с другом, чем функции, создающие побочные эффекты.

Чистая функция – особый вид функции, возвращающей значения, которая не только не имеет побочных эффектов, но и не зависит от побочных эффектов остального кода – к примеру, не работает с глобальными переменными, которые могут быть случайно изменены где-то ещё. Чистая функция, будучи вызванной с одними и теми же аргументами, возвращает один и тот же результат (и больше ничего не делает) – что довольно приятно. С ней просто работать. Вызов такой функции можно мысленно заменять результатом её работы, без изменения смысла кода. Когда вы хотите проверить такую функцию, вы можете просто вызвать её, и быть уверенным, что если она работает в данном контексте, она будет работать в любом. Не такие чистые функции могут возвращать разные результаты в зависимости от многих факторов, и иметь побочные эффекты, которые сложно проверять и учитывать.