JavaScript с нуля - [20]

Шрифт
Интервал

://forum.kirupa.com, где я и другие разработчики с радостью помогут вам.

КОРОТКО О ГЛАВНОМ

Место размещения переменных в коде имеет огромное влияние на то, где они могут использоваться. Переменные, объявленные глобально, доступны по всему приложению. Переменные, объявленные локально, — только внутри области, в которой расположены. Внутри диапазона глобальных и локальных переменных у JavaScript есть огромное количество действий в запасе.

Эта глава представила обзор аспектов влияния области переменных на ваш код. В ближайшем будущем вам предстоит встретиться с некоторыми наиболее актуальными из этих аспектов.

9. Замыкания

Вероятно, что к этому моменту вы уже знаете все о функциях и обо всех их забавных особенностях. Важная часть работы с функциями, JavaScript и (возможно) жизнью в целом — это понимание замыканий. На рис. 9.1 замыкание обозначено серой областью, в которой пересекаются области функций и переменных.

Рис. 9.1. Замыкания

Больше ничего не буду говорить о замыканиях — лучше всего за них скажет сам код. Как бы я ни пытался сейчас их описать, это только еще больше вас запутает. В последующих разделах мы начнем со знакомого нам материала и будем постепенно продвигаться вглубь вражеской территории, населенной замыканиями.

Поехали!

Функции внутри функций

Первое, что мы сделаем, — проясним, что происходит, когда вы используете функции внутри функций, причем внутренняя функция возвращается. Для начала рассмотрим короткий пример.

Взгляните на этот код:

function calculateRectangleArea(length, width) {

return length * width;

}


let roomArea = calculateRectangleArea(10, 10);

alert(roomArea);

Функция calculateRectangleArea получает два аргумента и возвращает результат их умножения туда, откуда пришел вызов. В данном примере роль стороны, направившей вызов, играет переменная roomArea.

После выполнения этого кода переменная roomArea содержит результат умножения 10 на 10, равный 100 (рис. 9.2).

Рис. 9.2. Результат roomArea

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

Ниже представлен простейший пример того, что я имею в виду:

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;

}

На практике мы будем сталкиваться с подобной ситуацией очень редко. Зачастую у нас будут переменные и данные, используемые совместно как внешней, так и внутренней функцией. Для наглядности посмотрим на такой пример:


Рекомендуем почитать
Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


MFC и OpenGL

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


Симуляция частичной специализации

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


Обработка событий в С++

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


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.