>function power(base, exponent) {
> if (exponent == undefined)
> exponent = 2;
> var result = 1;
> for (var count = 0; count < exponent; count++)
> result *= base;
> return result;
>}
>console.log(power(4));
>// → 16
>console.log(power(4, 3));
>// → 64
В следующей главе мы увидим, как в теле функции можно узнать точное число переданных ей аргументов. Это полезно, т. к. позволяет создавать функцию, принимающую любое количество аргументов. К примеру, >console.log
использует это свойство, и выводит все переданные ей аргументы:
>console.log("R", 2, "D", 2);
>// → R 2 D 2
Возможность использовать вызовы функций как переменные вкупе с тем фактом, что локальные переменные каждый раз при вызове функции создаются заново, приводит нас к интересному вопросу. Что происходит с локальными переменными, когда функция перестаёт работать?
Следующий пример иллюстрирует этот вопрос. В нём объявляется функция >wrapValue
, которая создаёт локальную переменную. Затем она возвращает функцию, которая читает эту локальную переменную и возвращает её значение.
>function wrapValue(n) {
> var localVariable = n;
> return function() { return localVariable; };
>}
>var wrap1 = wrapValue(1);
>var wrap2 = wrapValue(2);
>console.log(wrap1());
>// → 1
>console.log(wrap2());
>// → 2
Это допустимо и работает так, как должно – доступ к переменной остаётся. Более того, в одно и то же время могут существовать несколько экземпляров одной и той же переменной, что ещё раз подтверждает тот факт, что с каждым вызовом функции локальные переменные пересоздаются.
Эта возможность работать со ссылкой на какой-то экземпляр локальной переменной называется замыканием. Функция, замыкающая локальные переменные, называется замыкающей. Она не только освобождает вас от забот, связанных с временем жизни переменных, но и позволяет творчески использовать функции.
С небольшим изменением мы превращаем наш пример в функцию, умножающую числа на любое заданное число.
>function multiplier(factor) {
> return function(number) {
> return number * factor;
> };
>}
>var twice = multiplier(2);
>console.log(twice(5));
>// → 10
Отдельная переменная вроде >localVariable
из примера с >wrapValue
уже не нужна. Так как параметр – сам по себе локальная переменная.
Потребуется практика, чтобы начать мыслить подобным образом. Хороший вариант мысленной модели – представлять, что функция замораживает код в своём теле и обёртывает его в упаковку. Когда вы видите >return function(...) {...}
, представляйте, что это пульт управления куском кода, замороженным для употребления позже.
В нашем примере