Ниже представлен простейший пример того, что я имею в виду:
function youSayGoodBye() {
alert("Good Bye!");
function andISayHello() {
alert("Hello!");
}
return andISayHello;
}
У нас могут быть функции, содержащие в себе другие функции. В данном примере есть функция youSayGoodbye, которая содержит alert и функцию andISayHello (рис. 9.3).
Рис. 9.3. Функция внутри функции
В этом примере интересно то, что возвращает функция youSayGoodbye, когда ее вызывают. А возвращает она функцию andISayHello:
function youSayGoodBye() {
alert("Good Bye!");
function andISayHello() {
alert("Hello!");
}
return andISayHello;
}
Попрактикуемся на таком примере. Для вызова функции инициализируем переменную, указывающую на youSayGoodBye:
let something = youSayGoodBye();
В момент выполнения этой строки кода будет также выполнен весь код внутри функции youSayGoodBye. Это значит, что вы увидите диалоговое окно (благодаря alert), говорящее нам Good Bye! (рис. 9.4).
Рис. 9.4. Диалоговое окно Good Bye!
Как часть процесса выполнения до завершения функция andISayHello будет также создана и затем возвращена. В этот момент наша переменная — something, способная обратиться только к одному элементу, а именно к функции andISayHello (рис. 9.5).
Рис. 9.5. Переменная something и функция andISayHello
С точки зрения переменной something внешняя функция youSayGoodBye просто исчезает. Так как теперь переменная something указывает на функцию, вы можете активировать эту функцию, вызвав ее, как обычно, с помощью открывающих и закрывающих скобок:
let something = youSayGoodBye();
something();
Когда вы это сделаете, произойдет выполнение внутренней возвращенной функции (то есть andISayHello). Как и раньше, ждите появления диалогового окна, но теперь оно скажет Hello! (рис. 9.6), что определено в alert внутри этой функции.
Рис. 9.6. Hello!
Все это скорее похоже на обзор. Единственное новое, о чем вы могли узнать, — это то, что как только функция возвращает значение, она уходит из поля действия. Остается только возвращенное значение.
Хорошо. А теперь, как я и обещал, мы подобрались к границе вражеской территории. В следующем разделе дополним только что пройденный материал, рассмотрев схожий пример, но с некоторой особенностью.
Когда внутренние функции независимы
В предыдущем примере внутренняя функция andISayHello была самостоятельной и не опиралась ни на какие переменные или состояние внешней функции:
function youSayGoodBye() {
alert("Good Bye!");
function andISayHello() {
alert("Hello!");
}
return andISayHello;
}
На практике мы будем сталкиваться с подобной ситуацией очень редко. Зачастую у нас будут переменные и данные, используемые совместно как внешней, так и внутренней функцией. Для наглядности посмотрим на такой пример:
function stopWatch() {
let startTime = Date.now();
function getDelay() {
let elapsedTime = Date.now() — startTime;
alert(elapsedTime);
}
return getDelay;
}
Здесь показан очень простой способ измерения времени, необходимого для какого-либо действия. Внутри функции stopWatch мы видим переменную, для которой установлено значение Date.now():
function stopWatch() {
let startTime = Date.now();
function getDelay() {
let elapsedTime = Date.now() — startTime;
alert(elapsedTime);
}
return getDelay;
}
У нас также есть внутренняя функция getDelay:
function stopWatch() {
let startTime = Date.now();
function getDelay() {
let elapsedTime = Date.now() — startTime;
alert(elapsedTime);
}
return getDelay;
}
Функция getDelay отображает диалоговое окно, содержащее разницу во времени между новым вызовом Date.now() и ранее объявленной переменной startTime.
Что касается функции stopWatch, то последнее, что она делает перед завершением, — это возврат функции getDelay. Как мы можем увидеть, этот код очень похож на код из предыдущего примера. У нас есть внешняя и внутренняя функции, а также внешняя функция, возвращающая внутреннюю.
Теперь, чтобы увидеть stopWatch в действии, добавьте следующие строки кода: