Выразительный 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 медленнее, чем версия с циклом. Проход по циклу выходит дешевле, чем вызов функции.
Дилемма «скорость против элегантности» довольно интересна. Есть некий промежуток между удобством для человека и удобством для машины. Любую программу можно ускорить, сделав её больше и замысловатее. От программиста требуется находить подходящий баланс.
В случае с первым возведением в степень, неэлегантный цикл довольно прост и понятен. Не имеет смысла заменять его рекурсией. Часто, однако, программы работают с такими сложными концепциями, что хочется уменьшить эффективность путём повышения читаемости.
Основное правило, которое уже не раз повторяли, и с которым я полностью согласен – не беспокойтесь насчёт быстродействия, пока вы точно не уверены, что программа тормозит. Если так, найдите те части, которые работают дольше всех, и меняйте там элегантность на эффективность.