Выразительный JavaScript | страница 28



С небольшим изменением мы превращаем наш пример в функцию, умножающую числа на любое заданное число.

>function multiplier(factor) {

>  return function(number) {

>    return number * factor;

>  };

>}


>var twice = multiplier(2);

>console.log(twice(5));

>// → 10

Отдельная переменная вроде >localVariable из примера с >wrapValue уже не нужна. Так как параметр – сам по себе локальная переменная.

Потребуется практика, чтобы начать мыслить подобным образом. Хороший вариант мысленной модели – представлять, что функция замораживает код в своём теле и обёртывает его в упаковку. Когда вы видите >return function(...) {...}, представляйте, что это пульт управления куском кода, замороженным для употребления позже.

В нашем примере >multiplier возвращает замороженный кусок кода, который мы сохраняем в переменной >twice. Последняя строка вызывает функцию, заключённую в переменной, в связи с чем активируется сохранённый код (>return number * factor;). У него всё ещё есть доступ к переменной >factor, которая определялась при вызове >multiplier, к тому же у него есть доступ к аргументу, переданному во время разморозки >(5) в качестве числового параметра.

Рекурсия

Функция вполне может вызывать сама себя, если она заботится о том, чтобы не переполнить стек. Такая функция называется рекурсивной. Вот пример альтернативной реализации возведения в степень:

>function power(base, exponent) {

>  if (exponent == 0)

>    return 1;

>  else

>    return base * power(base, exponent - 1);

>}


>console.log(power(2, 3));

>// → 8

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

Однако, у такой реализации есть проблема – в обычной среде JavaScript она раз в 10 медленнее, чем версия с циклом. Проход по циклу выходит дешевле, чем вызов функции.

Дилемма «скорость против элегантности» довольно интересна. Есть некий промежуток между удобством для человека и удобством для машины. Любую программу можно ускорить, сделав её больше и замысловатее. От программиста требуется находить подходящий баланс.

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

Основное правило, которое уже не раз повторяли, и с которым я полностью согласен – не беспокойтесь насчёт быстродействия, пока вы точно не уверены, что программа тормозит. Если так, найдите те части, которые работают дольше всех, и меняйте там элегантность на эффективность.